# HG changeset patch # User Paul Boddie # Date 1629847688 -7200 # Node ID 49d8e9637cdb79899bbf1e8e7e63217e3feaa0c7 # Parent 40dc1cbd5356a31d28e76a4b8eb3b848c142d5eb Introduced various external packages into this distribution. Some small changes were made to Control files upon discovering build issues, and libext2fs/lib/Makefile was adjusted to enforce build ordering. diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/Control --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/Control Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,3 @@ +requires: libc libext2fs libsystypes +provides: libe2access +maintainer: paul@boddie.org.uk diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,4 @@ +PKGDIR ?= . +L4DIR ?= $(PKGDIR)/../../.. + +include $(L4DIR)/mk/subdir.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/docs/COPYING-GPL-2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/docs/COPYING-GPL-2 Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,1 @@ +LICENCE.txt \ No newline at end of file diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/docs/COPYING.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/docs/COPYING.txt Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,22 @@ +Licence Agreement +----------------- + +All original work in this distribution is covered by the following copyright +and licensing information: + +Copyright (C) 2019 Paul Boddie + +This software 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 software 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 library; see the file LICENCE.txt +If not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/docs/LICENCE.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/docs/LICENCE.txt Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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 + + 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) + + 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. + +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) year 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 Lesser General +Public License instead of this License. diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/include/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,7 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../../.. + +PKGNAME = libe2access +CONTRIB_HEADERS = 1 + +include $(L4DIR)/mk/include.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/include/e2access/access.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/include/e2access/access.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,32 @@ +/* + * Access control functions. + * + * Copyright (C) 2019 Paul Boddie + * + * 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 + */ + +#pragma once + +#include +#include + +EXTERN_C_BEGIN + +int access_can_read(user_t user, struct ext2_inode *inode); +int access_can_write(user_t user, struct ext2_inode *inode); + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/include/e2access/format.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/include/e2access/format.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,37 @@ +/* + * File metadata formatting. + * + * Copyright (C) 2019 Paul Boddie + * + * 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 __FORMAT_H__ +#define __FORMAT_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +char *get_permission_string(uint16_t permissions); + +#ifdef __cplusplus +} +#endif + +#endif /* __FORMAT_H__ */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/include/e2access/image.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/include/e2access/image.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,79 @@ +/* + * Filesystem image access functions. + * + * Copyright (C) 2019 Paul Boddie + * + * 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 __IMAGE_H__ +#define __IMAGE_H__ + +#include + + + +#ifdef __cplusplus +extern "C" { +#endif + +errcode_t image_create_file(ext2_filsys fs, ext2_ino_t ino_target, + const char *basename, __u16 mode, + __u16 uid, __u16 gid, ext2_ino_t *ino_file); + +errcode_t image_find_next(ext2_filsys fs, ext2_ino_t ino_dir, + const char **basename, char *buf, ext2_ino_t *ino); + +errcode_t image_find_path(ext2_filsys fs, const char **pathname, + ext2_ino_t *ino); + +errcode_t image_find_file(ext2_filsys fs, const char *dirname, + const char *basename, ext2_ino_t *ino); + +errcode_t image_inode(ext2_filsys fs, const char *pathname, + struct ext2_inode *inode); + +errcode_t image_make_dir(ext2_filsys fs, ext2_ino_t ino_dir, + const char *basename, __u16 mode, + __u16 uid, __u16 gid, ext2_ino_t *ino); + +errcode_t image_make_next_dir(ext2_filsys fs, ext2_ino_t ino_dir, + const char **basename, __u16 mode, __u16 uid, + __u16 gid, ext2_ino_t *ino); + +errcode_t image_make_dirs(ext2_filsys fs, const char **pathname, + ext2_ino_t ino_dir, __u16 mode, __u16 uid, + __u16 gid); + +void image_set_metadata(struct ext2_inode *inode, int clean, __u16 mode, + __u16 uid, __u16 gid); + +errcode_t image_stat_inode(ext2_filsys fs, ext2_ino_t ino, struct stat *st); + +int _image_isdir(ext2_filsys fs, ext2_ino_t ino); + +int image_isdir(ext2_filsys fs, const char *name); + +int _image_isfile(ext2_filsys fs, ext2_ino_t ino); + +int image_isfile(ext2_filsys fs, const char *name); + +#ifdef __cplusplus +} +#endif + + +#endif /* __IMAGE_H__ */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/include/e2access/path.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/include/e2access/path.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,38 @@ +/* + * Path functions. + * + * Copyright (C) 2019 Paul Boddie + * + * 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 __PATH_H__ +#define __PATH_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +const char *path_basename(const char *path); +const char *path_component_end(const char *path); +const char *path_component_next(const char *end); +int path_is_leafname(const char *path); + +#ifdef __cplusplus +} +#endif + +#endif /* __PATH_H__ */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/lib/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/lib/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,4 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../../.. + +include $(L4DIR)/mk/subdir.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/lib/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/lib/src/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../../.. + +TARGET = libe2access.a libe2access.so +PC_FILENAME = libe2access +SRC_C = access.c format.c image.c path.c + +REQUIRES_LIBS = libext2fs libsystypes + +PRIVATE_INCDIR = $(PKGDIR)/include/e2access +CONTRIB_INCDIR = libe2access + +include $(L4DIR)/mk/lib.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/lib/src/access.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/lib/src/access.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,42 @@ +/* + * Access control functions. + * + * Copyright (C) 2019 Paul Boddie + * + * 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 "access.h" + +int access_can_read(user_t user, struct ext2_inode *inode) +{ + /* NOTE: Could use a generic function for properly testing access. + NOTE: For example, this does not permit multiple groups. */ + + return ((inode->i_uid == user.uid) && (inode->i_mode & LINUX_S_IRUSR)) || + ((inode->i_gid == user.gid) && (inode->i_mode & LINUX_S_IRGRP)) || + (inode->i_mode & LINUX_S_IROTH); +} + +int access_can_write(user_t user, struct ext2_inode *inode) +{ + /* NOTE: Could use a generic function for properly testing access. + NOTE: For example, this does not permit multiple groups. */ + + return ((inode->i_uid == user.uid) && (inode->i_mode & LINUX_S_IWUSR)) || + ((inode->i_gid == user.gid) && (inode->i_mode & LINUX_S_IWGRP)) || + (inode->i_mode & LINUX_S_IWOTH); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/lib/src/format.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/lib/src/format.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,39 @@ +/* + * File metadata formatting. + * + * Copyright (C) 2019 Paul Boddie + * + * 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 "format.h" + + + +/* Return the permissions of an object as a string. */ + +char *get_permission_string(uint16_t permissions) +{ + static char s[9] = "--------\0"; + static char letters[] = "rwx"; + int i, letter; + uint16_t selector = 0400; + + for (i = 0, letter = 0; i < 9; i++, letter = (letter + 1) % 3, selector >>= 1) + s[i] = permissions & selector ? letters[letter] : '-'; + + return s; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/lib/src/image.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/lib/src/image.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,343 @@ +/* + * Filesystem access functions. + * + * Copyright (C) 2019 Paul Boddie + * + * 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 +#include + +#include + +#include "image.h" +#include "path.h" + + + +/* Create an inode for a file. */ + +errcode_t image_create_file(ext2_filsys fs, ext2_ino_t ino_target, + const char *basename, __u16 mode, + __u16 uid, __u16 gid, ext2_ino_t *ino_file) +{ + struct ext2_inode inode_file; + errcode_t retval; + + /* Without an inode, create a new one. */ + + retval = ext2fs_new_inode(fs, ino_target, LINUX_S_IFREG | mode, 0, ino_file); + if (retval) + return retval; + + /* Connect the inode to its parent. */ + + while (1) + { + retval = ext2fs_link(fs, ino_target, basename, *ino_file, + EXT2_FT_REG_FILE); + + if (!retval) + break; + + /* Expand the directory if necessary. */ + + if (retval == EXT2_ET_DIR_NO_SPACE) + retval = ext2fs_expand_dir(fs, ino_target); + + if (retval) + return retval; + } + + /* Make sure that subsequent files employ different inodes. */ + + ext2fs_inode_alloc_stats2(fs, *ino_file, 1, 0); + + /* Populate the inode details. */ + + image_set_metadata(&inode_file, 1, LINUX_S_IFREG | mode, uid, gid); + + return ext2fs_write_new_inode(fs, *ino_file, &inode_file); +} + +/* Set the mode, user and group metadata for a file. */ + +void image_set_metadata(struct ext2_inode *inode, int clean, __u16 mode, + __u16 uid, __u16 gid) +{ + if (clean) + memset(inode, 0, sizeof(*inode)); + + inode->i_mode = mode; + inode->i_uid = uid; + inode->i_gid = gid; +} + +/* Find an object in the given directory with the given name in the filesystem + image, updating the name reference to refer to the next component. */ + +errcode_t image_find_next(ext2_filsys fs, ext2_ino_t ino_dir, + const char **basename, char *buf, ext2_ino_t *ino) +{ + const char *end = path_component_end(*basename); + errcode_t retval; + + /* Find the basename in the directory. */ + + retval = ext2fs_lookup(fs, ino_dir, *basename, end - *basename, buf, ino); + + /* Update the current component. */ + + if (!retval) + *basename = path_component_next(end); + + return retval; +} + +/* Find an object with the given pathname in the filesystem image. */ + +errcode_t image_find_path(ext2_filsys fs, const char **pathname, ext2_ino_t *ino) +{ + char *buf; + ext2_ino_t ino_dir; + errcode_t retval; + + retval = ext2fs_get_mem(fs->blocksize, &buf); + if (retval) + return retval; + + /* Skip any leading root marker. */ + + if (**pathname == '/') + (*pathname)++; + + if (!**pathname) + *ino = EXT2_ROOT_INO; + + /* Start at the root. */ + + ino_dir = EXT2_ROOT_INO; + + /* With any remaining path, find the next component. */ + + while (**pathname) + { + retval = image_find_next(fs, ino_dir, pathname, buf, ino); + if (retval) + { + *ino = ino_dir; + break; + } + + /* Move into the found object for searching the next component. */ + + ino_dir = *ino; + } + + ext2fs_free_mem(&buf); + + return retval; +} + +/* Find an object in the given directory with the given name in the filesystem + image. */ + +errcode_t image_find_file(ext2_filsys fs, const char *dirname, + const char *basename, ext2_ino_t *ino) +{ + char pathname[strlen(dirname) + strlen(basename) + 2]; + const char *s = pathname; + + strcpy(pathname, dirname); + strcat(pathname, "/"); + strcat(pathname, basename); + + return image_find_path(fs, &s, ino); +} + +/* Obtain the inode for the object with the given pathname in the filesystem + image. */ + +errcode_t image_inode(ext2_filsys fs, const char *pathname, + struct ext2_inode *inode) +{ + ext2_ino_t ino; + errcode_t retval; + + retval = image_find_path(fs, &pathname, &ino); + if (retval) + return retval; + + return ext2fs_read_inode(fs, ino, inode); +} + +/* Make a directory in the given directory in the filesystem image having the + given name and metadata. */ + +errcode_t image_make_dir(ext2_filsys fs, ext2_ino_t ino_dir, + const char *basename, __u16 mode, + __u16 uid, __u16 gid, ext2_ino_t *ino) +{ + struct ext2_inode inode_dir; + errcode_t retval = 0; + + /* Create an inode in the directory. */ + + retval = ext2fs_new_inode(fs, ino_dir, LINUX_S_IFDIR | mode, 0, ino); + if (retval) + return retval; + + /* Make the directory and update the metadata (due to ext2fs_mkdir + limitation). */ + + retval = ext2fs_mkdir(fs, ino_dir, *ino, basename); + if (retval) + return retval; + + retval = ext2fs_read_inode(fs, *ino, &inode_dir); + if (retval) + return retval; + + image_set_metadata(&inode_dir, 0, LINUX_S_IFDIR | mode, uid, gid); + return ext2fs_write_inode(fs, *ino, &inode_dir); +} + +/* Make a directory in the given directory in the filesystem image, updating + the name reference to refer to the next component. */ + +errcode_t image_make_next_dir(ext2_filsys fs, ext2_ino_t ino_dir, + const char **basename, __u16 mode, __u16 uid, + __u16 gid, ext2_ino_t *ino) +{ + char *end = (char *) path_component_end(*basename); + char endchar = *end; + errcode_t retval = 0; + + /* Delimit the basename and make a directory using the inode. */ + + if (endchar) + *end = '\0'; + + /* Do not create directories for empty components. */ + + if (**basename) + retval = image_make_dir(fs, ino_dir, *basename, mode, uid, gid, ino); + + /* Restore the path separator and update the current component. */ + + if (endchar) + *end = '/'; + + if (!retval) + *basename = path_component_next(end); + + return retval; +} + +/* Make directories descending to the given path in the filesystem image. */ + +errcode_t image_make_dirs(ext2_filsys fs, const char **pathname, + ext2_ino_t ino_dir, __u16 mode, __u16 uid, __u16 gid) +{ + ext2_ino_t ino; + errcode_t retval; + + while (**pathname) + { + retval = image_make_next_dir(fs, ino_dir, pathname, mode, uid, gid, &ino); + if (retval) + return retval; + + /* Move into the created object for handling the next component. */ + + ino_dir = ino; + } + + return 0; +} + +/* Copy file metadata into a stat structure. */ + +errcode_t image_stat_inode(ext2_filsys fs, ext2_ino_t ino, struct stat *st) +{ + struct ext2_inode inode; + errcode_t retval = ext2fs_read_inode(fs, ino, &inode); + + if (retval) + return retval; + + st->st_dev = 0; /* device identifier */ + st->st_ino = ino; + st->st_mode = inode.i_mode; + st->st_nlink = inode.i_links_count; + st->st_uid = inode_uid(inode); + st->st_gid = inode_gid(inode); + st->st_rdev = 0; /* special file device identifier */ + st->st_size = EXT2_I_SIZE(&inode); + st->st_blksize = fs->blocksize; + st->st_blocks = 0; /* number of 512 byte blocks allocated */ + st->st_atim.tv_sec = inode.i_atime; + st->st_atim.tv_nsec = 0; /* nanosecond resolution */ + st->st_mtim.tv_sec = inode.i_mtime; + st->st_mtim.tv_nsec = 0; + st->st_ctim.tv_sec = inode.i_ctime; + st->st_ctim.tv_nsec = 0; + + return 0; +} + +/* Test object types in the filesystem image. */ + +int _image_isdir(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_inode inode; + + if (ext2fs_read_inode(fs, ino, &inode)) + return 0; + + return LINUX_S_ISDIR(inode.i_mode); +} + +int image_isdir(ext2_filsys fs, const char *name) +{ + ext2_ino_t ino; + + if (image_find_path(fs, &name, &ino)) + return 0; + + return _image_isdir(fs, ino); +} + +int _image_isfile(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_inode inode; + + if (ext2fs_read_inode(fs, ino, &inode)) + return 0; + + return LINUX_S_ISREG(inode.i_mode); +} + +int image_isfile(ext2_filsys fs, const char *name) +{ + ext2_ino_t ino; + + if (image_find_path(fs, &name, &ino)) + return 0; + + return _image_isfile(fs, ino); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libe2access/lib/src/path.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/lib/src/path.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,66 @@ +/* + * Path functions. + * + * Copyright (C) 2019 Paul Boddie + * + * 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 + +#include "path.h" + +/* Return the basename from a path. */ + +const char *path_basename(const char *path) +{ + char *s = strrchr(path, (int) '/'); + + if (s == NULL) + return path; + else + return s + 1; +} + +/* Return the end of the first component in the given path. */ + +const char *path_component_end(const char *path) +{ + char *end = strchr(path, (int) '/'); + + if (end == NULL) + return path + strlen(path); + else + return end; +} + +/* Return the start of the next component in a path given the end of the + previous one. */ + +const char *path_component_next(const char *end) +{ + if (*end) + return end + 1; + else + return end; +} + +/* Return whether the path lacks a path separator. */ + +int path_is_leafname(const char *path) +{ + return strchr(path, (int) '/') == NULL; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/Control --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/Control Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,3 @@ +requires: libc libc_support_misc +provides: libblkid libe2p libet libext2fs libsupport libuuid +maintainer: paul@boddie.org.uk diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,4 @@ +PKGDIR ?= . +L4DIR ?= $(PKGDIR)/../../.. + +include $(L4DIR)/mk/subdir.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/NOTICE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/NOTICE Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,849 @@ +This package, the EXT2 filesystem utilities, are made available under +the GNU Public License version 2, with the exception of the lib/ext2fs +and lib/e2p libraries, which are made available under the GNU Library +General Public License Version 2, the lib/uuid library which is made +available under a BSD-style license and the lib/et and lib/ss +libraries which are made available under an MIT-style license. Please +see lib/uuid/COPYING for more details for the license for the files +comprising the libuuid library, and the source file headers of the +libet and libss libraries for more information. + +The most recent officially distributed version can be found at +http://e2fsprogs.sourceforge.net. If you need to make a distribution, +that's the one you should use. If there is some reason why you'd like +a more recent version that is still in ALPHA testing (i.e., either +using the "WIP" test distributions or one from the hg or git +repository from the development branch, please contact me +(tytso@mit.edu) before you ship. The release schedules for this +package are flexible, if you give me enough lead time. + + + Theodore Ts'o + 23-June-2007 + +---------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 + + 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) + + 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 + + +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) year 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. + +---------------------------------------------------------------------- + + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, 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 library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, 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 companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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) + + This library 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 of the License, or (at your option) any later version. + + This library 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/docs/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/docs/README Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,19 @@ + This is the new version (1.44.5) of the second extended file +system management programs. + + From time to time, I release new versions of e2fsprogs, to fix +bugs and to make the utilities more robust. You can always find +information about the latest version at the the e2fsprogs web page, +which is: + + http://e2fsprogs.sourceforge.net + + The INSTALL file has instructions on building and installing +e2fsprogs. Provisions for building Red Hat RPMs and Debian dpkg files +are supplied as well. + + In case of bugs in these programs, please contact Ted Ts'o at +tytso@mit.edu or tytso@alum.mit.edu. See the e2fsck man page for +suggestions of what sort of information to include when submitting bug +reports for these programs. + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/docs/RELEASE-NOTES --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/docs/RELEASE-NOTES Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,77 @@ +E2fsprogs 1.44.5 (December 15, 2018) +==================================== + +Updates/Fixes since v1.44.4: + +UI and Features +--------------- + +When e2fsck notices it could optimize an extent tree, it will now ask +"Optimize?" instead of "Fix?", which was confusing some users since it +implied that something was broken. + + +Fixes +----- + +Use 64-bit counters to track the number of files that are defragmented +using in e4defrag, to avoid overflows when more than 2**32 files are +defragmented. (Addresses Debian Bug: #888899) + +Correctly translate Posix ACL's. This was a regression introduced in +v1.44.4. (Addresses Launchpad Bug: #1807288) + +Use the online free block counts so e2freefrag's percentages are +correct. + +Fix a false warning that tune2fs will take long time to change a UUID if +the metadata_csum feature is not enabled. + +E2fsck will only offer to set the inline_data feature flag when the +inline flag is set on the inode, *and* the system.data xattr is present. + +E4defrag will handle the case where it is running as root and it can't +find the file system to open more gracefully. (Addresses Debian Bug: +#907634) + +Fix a bug where resize2fs was failing to update the extent tree +checksums in an corner case. (Addresses Launchpad Bug: #1798562) + +Fix fuse2fs's command line parsing when options are specified after the +target device/image. + +Fix a bug which could cause e2fsprogs tools to segfault on a corrupted +file system where the journal's s_nr_users is impossibly large. + +E2image now includes the mmp block (if needed) when creating a +metadata-only image. + +If various Verity handling bugs which made it completely unusable in +e2fsprogs 1.44.4. + +Fox a bug in tune2fs where it would dereference of freed memory after +replaying the journal. + + +Performance, Internal Implementation, Development Support etc. +-------------------------------------------------------------- + +Synchronized changes from Android's AOSP e2fsprogs tree. + +Fix groff formatting nits in various man pages. (Addresses Debian Bug: +#916188) + +Fixed various debian packaging issues (Addresses Debian Bug: #915942) + +Adjusted the copyright license for lib/blkid/version.c to be LGPL (and +consistent with the rest of files in that directory). + +Fix various clang warnings. + +Fix "make install" when configure was run with --enable-subset. + +Make sure the regression tests clean up their tmpfile if the test script +exits. + +Fix build failures on non-glibc systems. + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,6 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../../.. + +TARGET := libuuid libblkid libsupport libe2p libet libext2fs + +include $(L4DIR)/mk/subdir.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libblkid/blkid/blkid.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libblkid/blkid/blkid.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,110 @@ +/* + * blkid.h - Interface for libblkid, a library to identify block devices + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#ifndef _BLKID_BLKID_H +#define _BLKID_BLKID_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLKID_VERSION "1.0.0" +#define BLKID_DATE "12-Feb-2003" + +typedef struct blkid_struct_dev *blkid_dev; +typedef struct blkid_struct_cache *blkid_cache; +typedef __s64 blkid_loff_t; + +typedef struct blkid_struct_tag_iterate *blkid_tag_iterate; +typedef struct blkid_struct_dev_iterate *blkid_dev_iterate; + +/* + * Flags for blkid_get_dev + * + * BLKID_DEV_CREATE Create an empty device structure if not found + * in the cache. + * BLKID_DEV_VERIFY Make sure the device structure corresponds + * with reality. + * BLKID_DEV_FIND Just look up a device entry, and return NULL + * if it is not found. + * BLKID_DEV_NORMAL Get a valid device structure, either from the + * cache or by probing the device. + */ +#define BLKID_DEV_FIND 0x0000 +#define BLKID_DEV_CREATE 0x0001 +#define BLKID_DEV_VERIFY 0x0002 +#define BLKID_DEV_NORMAL (BLKID_DEV_CREATE | BLKID_DEV_VERIFY) + +/* cache.c */ +extern void blkid_put_cache(blkid_cache cache); +extern int blkid_get_cache(blkid_cache *cache, const char *filename); +extern void blkid_gc_cache(blkid_cache cache); + +/* dev.c */ +extern const char *blkid_dev_devname(blkid_dev dev); + +extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache); +extern int blkid_dev_set_search(blkid_dev_iterate iter, + char *search_type, char *search_value); +extern int blkid_dev_next(blkid_dev_iterate iterate, blkid_dev *dev); +extern void blkid_dev_iterate_end(blkid_dev_iterate iterate); + +/* devno.c */ +extern char *blkid_devno_to_devname(dev_t devno); + +/* devname.c */ +extern int blkid_probe_all(blkid_cache cache); +extern int blkid_probe_all_new(blkid_cache cache); +extern blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, + int flags); + +/* getsize.c */ +extern blkid_loff_t blkid_get_dev_size(int fd); + +/* probe.c */ +int blkid_known_fstype(const char *fstype); +extern blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev); + +/* read.c */ + +/* resolve.c */ +extern char *blkid_get_tag_value(blkid_cache cache, const char *tagname, + const char *devname); +extern char *blkid_get_devname(blkid_cache cache, const char *token, + const char *value); + +/* tag.c */ +extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev); +extern int blkid_tag_next(blkid_tag_iterate iterate, + const char **type, const char **value); +extern void blkid_tag_iterate_end(blkid_tag_iterate iterate); +extern int blkid_dev_has_tag(blkid_dev dev, const char *type, + const char *value); +extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache, + const char *type, + const char *value); +extern int blkid_parse_tag_string(const char *token, char **ret_type, + char **ret_val); + +/* version.c */ +extern int blkid_parse_version_string(const char *ver_string); +extern int blkid_get_library_version(const char **ver_string, + const char **date_string); + +#ifdef __cplusplus +} +#endif + +#endif /* _BLKID_BLKID_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libblkid/blkid/blkid_types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libblkid/blkid/blkid_types.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,174 @@ +/* + * If linux/types.h is already been included, assume it has defined + * everything we need. (cross fingers) Other header files may have + * also defined the types that we need. + */ +#if (!defined(_LINUX_TYPES_H) && !defined(_BLKID_TYPES_H) && \ + !defined(_EXT2_TYPES_H)) +#define _BLKID_TYPES_H + +#define __S8_TYPEDEF __signed__ char +#define __U8_TYPEDEF unsigned char +#define __S16_TYPEDEF __signed__ short +#define __U16_TYPEDEF unsigned short +#define __S32_TYPEDEF __signed__ int +#define __U32_TYPEDEF unsigned int +#define __S64_TYPEDEF __signed__ long long +#define __U64_TYPEDEF unsigned long long + +#ifndef HAVE___U8 +#define HAVE___U8 +#ifdef __U8_TYPEDEF +typedef __U8_TYPEDEF __u8; +#else +typedef unsigned char __u8; +#endif +#endif /* HAVE___U8 */ + +#ifndef HAVE___S8 +#define HAVE___S8 +#ifdef __S8_TYPEDEF +typedef __S8_TYPEDEF __s8; +#else +typedef signed char __s8; +#endif +#endif /* HAVE___S8 */ + +#ifndef HAVE___U16 +#define HAVE___U16 +#ifdef __U16_TYPEDEF +typedef __U16_TYPEDEF __u16; +#else +#if (4 == 2) +typedef unsigned int __u16; +#else +#if (2 == 2) +typedef unsigned short __u16; +#else +#undef HAVE___U16 + ?==error: undefined 16 bit type +#endif /* SIZEOF_SHORT == 2 */ +#endif /* SIZEOF_INT == 2 */ +#endif /* __U16_TYPEDEF */ +#endif /* HAVE___U16 */ + +#ifndef HAVE___S16 +#define HAVE___S16 +#ifdef __S16_TYPEDEF +typedef __S16_TYPEDEF __s16; +#else +#if (4 == 2) +typedef int __s16; +#else +#if (2 == 2) +typedef short __s16; +#else +#undef HAVE___S16 + ?==error: undefined 16 bit type +#endif /* SIZEOF_SHORT == 2 */ +#endif /* SIZEOF_INT == 2 */ +#endif /* __S16_TYPEDEF */ +#endif /* HAVE___S16 */ + +#ifndef HAVE___U32 +#define HAVE___U32 +#ifdef __U32_TYPEDEF +typedef __U32_TYPEDEF __u32; +#else +#if (4 == 4) +typedef unsigned int __u32; +#else +#if (4 == 4) +typedef unsigned long __u32; +#else +#if (2 == 4) +typedef unsigned short __u32; +#else +#undef HAVE___U32 + ?== error: undefined 32 bit type +#endif /* SIZEOF_SHORT == 4 */ +#endif /* SIZEOF_LONG == 4 */ +#endif /* SIZEOF_INT == 4 */ +#endif /* __U32_TYPEDEF */ +#endif /* HAVE___U32 */ + +#ifndef HAVE___S32 +#define HAVE___S32 +#ifdef __S32_TYPEDEF +typedef __S32_TYPEDEF __s32; +#else +#if (4 == 4) +typedef int __s32; +#else +#if (4 == 4) +typedef long __s32; +#else +#if (2 == 4) +typedef short __s32; +#else +#undef HAVE___S32 + ?== error: undefined 32 bit type +#endif /* SIZEOF_SHORT == 4 */ +#endif /* SIZEOF_LONG == 4 */ +#endif /* SIZEOF_INT == 4 */ +#endif /* __S32_TYPEDEF */ +#endif /* HAVE___S32 */ + +#ifndef HAVE___U64 +#define HAVE___U64 +#ifdef __U64_TYPEDEF +typedef __U64_TYPEDEF __u64; +#else +#if (4 == 8) +typedef unsigned int __u64; +#else +#if (8 == 8) +typedef unsigned long long __u64; +#else +#if (4 == 8) +typedef unsigned long __u64; +#else +#undef HAVE___U64 + ?== error: undefined 64 bit type +#endif /* SIZEOF_LONG == 8 */ +#endif /* SIZEOF_LONG_LONG == 8 */ +#endif /* SIZEOF_INT == 8 */ +#endif /* __U64_TYPEDEF */ +#endif /* HAVE___U64 */ + +#ifndef HAVE___S64 +#define HAVE___S64 +#ifdef __S64_TYPEDEF +typedef __S64_TYPEDEF __s64; +#else +#if (4 == 8) +typedef int __s64; +#else +#if (8 == 8) +#if defined(__GNUC__) +typedef __signed__ long long __s64; +#else +typedef signed long long __s64; +#endif /* __GNUC__ */ +#else +#if (4 == 8) +typedef long __s64; +#else +#undef HAVE___S64 + ?== error: undefined 64 bit type +#endif /* SIZEOF_LONG == 8 */ +#endif /* SIZEOF_LONG_LONG == 8 */ +#endif /* SIZEOF_INT == 8 */ +#endif /* __S64_TYPEDEF */ +#endif /* HAVE___S64 */ + +#undef __S8_TYPEDEF +#undef __U8_TYPEDEF +#undef __S16_TYPEDEF +#undef __U16_TYPEDEF +#undef __S32_TYPEDEF +#undef __U32_TYPEDEF +#undef __S64_TYPEDEF +#undef __U64_TYPEDEF + +#endif /* _*_TYPES_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libblkid/blkid/list.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libblkid/blkid/list.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,184 @@ +#if !defined(_BLKID_LIST_H) && !defined(LIST_HEAD_INIT) +#define _BLKID_LIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_INTTYPES_H +#include +#else +#ifdef HAVE_STDINT_H +#include +#endif +#endif + +#ifdef __GNUC__ +#define _INLINE_ static __inline__ +#else /* For Watcom C */ +#define _INLINE_ static inline +#endif + +/* + * 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 INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +_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; +} + +/** + * list_add - add a new entry + * @add: 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. + */ +_INLINE_ void list_add(struct list_head *add, struct list_head *head) +{ + __list_add(add, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @add: 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. + */ +_INLINE_ void list_add_tail(struct list_head *add, struct list_head *head) +{ + __list_add(add, 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! + */ +_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. + * + * list_empty() on @entry does not return true after this, @entry is + * in an undefined state. + */ +_INLINE_ void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +_INLINE_ void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +_INLINE_ int list_empty(struct list_head *head) +{ + return head->next == head; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +_INLINE_ void list_splice(struct list_head *list, struct list_head *head) +{ + struct list_head *first = list->next; + + if (first != list) { + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; + } +} + +/** + * 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) \ + ((type *)((char *)(ptr)-(unsigned long)(intptr_t)(&((type *)0)->member))) + +/** + * list_for_each - iterate over elements in a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_safe - iterate over elements in a list, but don't dereference + * pos after the body is done (in case it is freed) + * @pos: the &struct list_head to use as a loop counter. + * @pnext: the &struct list_head to use as a pointer to the next item. + * @head: the head for your list (not included in iteration). + */ +#define list_for_each_safe(pos, pnext, head) \ + for (pos = (head)->next, pnext = pos->next; pos != (head); \ + pos = pnext, pnext = pos->next) + +#undef _INLINE_ + +#ifdef __cplusplus +} +#endif + +#endif /* _BLKID_LIST_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libe2p/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libe2p/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,7 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../../.. + +PKGNAME = libe2p +CONTRIB_HEADERS = 1 + +include $(L4DIR)/mk/include.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libe2p/e2p/e2p.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libe2p/e2p/e2p.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,82 @@ +/* + * e2p.h --- header file for the e2p library + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include /* Needed by dirent.h on netbsd */ +#include +#include + +#include + +#define E2P_FEATURE_COMPAT 0 +#define E2P_FEATURE_INCOMPAT 1 +#define E2P_FEATURE_RO_INCOMPAT 2 +#define E2P_FEATURE_TYPE_MASK 0x03 + +#define E2P_FEATURE_NEGATE_FLAG 0x80 + +#define E2P_FS_FEATURE 0 +#define E2P_JOURNAL_FEATURE 1 + +/* `options' for print_flags() */ + +#define PFOPT_LONG 1 /* Must be 1 for compatibility with `int long_format'. */ + + +int fgetflags (const char * name, unsigned long * flags); +int fgetversion (const char * name, unsigned long * version); +int fsetflags (const char * name, unsigned long flags); +int fsetversion (const char * name, unsigned long version); +int fgetproject(const char *name, unsigned long *project); +int fsetproject(const char *name, unsigned long project); +int getflags (int fd, unsigned long * flags); +int getversion (int fd, unsigned long * version); +int iterate_on_dir (const char * dir_name, + int (*func) (const char *, struct dirent *, void *), + void * private_arg); +void list_super(struct ext2_super_block * s); +void list_super2(struct ext2_super_block * s, FILE *f); +void print_fs_errors (FILE * f, unsigned short errors); +void print_flags (FILE * f, unsigned long flags, unsigned options); +void print_fs_state (FILE * f, unsigned short state); +int setflags (int fd, unsigned long flags); +int setversion (int fd, unsigned long version); + +void e2p_list_journal_super(FILE *f, char *journal_sb_buf, + int exp_block_size, int flags); + +const char *e2p_feature2string(int compat, unsigned int mask); +const char *e2p_jrnl_feature2string(int compat, unsigned int mask); +int e2p_string2feature(char *string, int *compat, unsigned int *mask); +int e2p_jrnl_string2feature(char *string, int *compat_type, unsigned int *mask); +int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array); +int e2p_edit_feature2(const char *str, __u32 *compat_array, __u32 *ok_array, + __u32 *clear_ok_array, int *type_err, + unsigned int *mask_err); + +int e2p_is_null_uuid(void *uu); +void e2p_uuid_to_str(void *uu, char *out); +const char *e2p_uuid2str(void *uu); + +const char *e2p_hash2string(int num); +int e2p_string2hash(char *string); + +const char *e2p_mntopt2string(unsigned int mask); +int e2p_string2mntopt(char *string, unsigned int *mask); +int e2p_edit_mntopts(const char *str, __u32 *mntopts, __u32 ok); + +unsigned long parse_num_blocks(const char *arg, int log_block_size); +unsigned long long parse_num_blocks2(const char *arg, int log_block_size); + +char *e2p_os2string(int os_type); +int e2p_string2os(char *str); + +unsigned int e2p_percent(int percent, unsigned int base); + +const char *e2p_encmode2string(int num); +int e2p_string2encmode(char *string); diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libet/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libet/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,7 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../../.. + +PKGNAME = libet +CONTRIB_HEADERS = 1 + +include $(L4DIR)/mk/include.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libet/et/com_err.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libet/et/com_err.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,68 @@ +/* + * Header file for common error description library. + * + * Copyright 1988, Student Information Processing Board of the + * Massachusetts Institute of Technology. + * + * For copyright and distribution info, see the documentation supplied + * with this package. + */ + +#if !defined(__COM_ERR_H) && !defined(__COM_ERR_H__) + +#ifdef __GNUC__ +#define COM_ERR_ATTR(x) __attribute__(x) +#else +#define COM_ERR_ATTR(x) +#endif + +#include +#include + +typedef long errcode_t; + +struct error_table { + char const * const * msgs; + long base; + int n_msgs; +}; +struct et_list; + +extern void com_err (const char *, long, const char *, ...) + COM_ERR_ATTR((format(printf, 3, 4))); + +extern void com_err_va (const char *whoami, errcode_t code, const char *fmt, + va_list args) + COM_ERR_ATTR((format(printf, 3, 0))); + +extern char const *error_message (long); +extern void (*com_err_hook) (const char *, long, const char *, va_list); +extern void (*set_com_err_hook (void (*) (const char *, long, + const char *, va_list))) + (const char *, long, const char *, va_list); +extern void (*reset_com_err_hook (void)) (const char *, long, + const char *, va_list); +extern int init_error_table(const char * const *msgs, long base, int count); +extern char *(*set_com_err_gettext (char *(*) (const char *))) + (const char *); + +extern errcode_t add_error_table(const struct error_table * et); +extern errcode_t remove_error_table(const struct error_table * et); +extern void add_to_error_table(struct et_list *new_table); + +/* Provided for Heimdall compatibility */ +extern const char *com_right(struct et_list *list, long code); +extern const char *com_right_r(struct et_list *list, long code, char *str, size_t len); +extern void initialize_error_table_r(struct et_list **list, + const char **messages, + int num_errors, + long base); +extern void free_error_table(struct et_list *et); + +/* Provided for compatibility with other com_err libraries */ +extern int et_list_lock(void); +extern int et_list_unlock(void); + +#define __COM_ERR_H +#define __COM_ERR_H__ +#endif /* !defined(__COM_ERR_H) && !defined(__COM_ERR_H__)*/ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libext2fs/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libext2fs/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,7 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../../.. + +PKGNAME = libext2fs +CONTRIB_HEADERS = 1 + +include $(L4DIR)/mk/include.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libext2fs/ext2fs/bitops.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libext2fs/ext2fs/bitops.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,703 @@ +/* + * bitops.h --- Bitmap frobbing code. The byte swapping routines are + * also included here. + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifdef WORDS_BIGENDIAN +#define ext2fs_cpu_to_le64(x) ((__force __le64)ext2fs_swab64((__u64)(x))) +#define ext2fs_le64_to_cpu(x) ext2fs_swab64((__force __u64)(__le64)(x)) +#define ext2fs_cpu_to_le32(x) ((__force __le32)ext2fs_swab32((__u32)(x))) +#define ext2fs_le32_to_cpu(x) ext2fs_swab32((__force __u32)(__le32)(x)) +#define ext2fs_cpu_to_le16(x) ((__force __le16)ext2fs_swab16((__u16)(x))) +#define ext2fs_le16_to_cpu(x) ext2fs_swab16((__force __u16)(__le16)(x)) + +#define ext2fs_cpu_to_be64(x) ((__force __be64)(__u64)(x)) +#define ext2fs_be64_to_cpu(x) ((__force __u64)(__be64)(x)) +#define ext2fs_cpu_to_be32(x) ((__force __be32)(__u32)(x)) +#define ext2fs_be32_to_cpu(x) ((__force __u32)(__be32)(x)) +#define ext2fs_cpu_to_be16(x) ((__force __be16)(__u16)(x)) +#define ext2fs_be16_to_cpu(x) ((__force __u16)(__be16)(x)) +#else +#define ext2fs_cpu_to_le64(x) ((__force __le64)(__u64)(x)) +#define ext2fs_le64_to_cpu(x) ((__force __u64)(__le64)(x)) +#define ext2fs_cpu_to_le32(x) ((__force __le32)(__u32)(x)) +#define ext2fs_le32_to_cpu(x) ((__force __u32)(__le32)(x)) +#define ext2fs_cpu_to_le16(x) ((__force __le16)(__u16)(x)) +#define ext2fs_le16_to_cpu(x) ((__force __u16)(__le16)(x)) + +#define ext2fs_cpu_to_be64(x) ((__force __be64)ext2fs_swab64((__u64)(x))) +#define ext2fs_be64_to_cpu(x) ext2fs_swab64((__force __u64)(__be64)(x)) +#define ext2fs_cpu_to_be32(x) ((__force __be32)ext2fs_swab32((__u32)(x))) +#define ext2fs_be32_to_cpu(x) ext2fs_swab32((__force __u32)(__be32)(x)) +#define ext2fs_cpu_to_be16(x) ((__force __be16)ext2fs_swab16((__u16)(x))) +#define ext2fs_be16_to_cpu(x) ext2fs_swab16((__force __u16)(__be16)(x)) +#endif + +/* + * EXT2FS bitmap manipulation routines. + */ + +/* Support for sending warning messages from the inline subroutines */ +extern const char *ext2fs_block_string; +extern const char *ext2fs_inode_string; +extern const char *ext2fs_mark_string; +extern const char *ext2fs_unmark_string; +extern const char *ext2fs_test_string; +extern void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg, + const char *description); +extern void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap, + int code, unsigned long arg); + +#ifdef NO_INLINE_FUNCS +extern void ext2fs_fast_set_bit(unsigned int nr,void * addr); +extern void ext2fs_fast_clear_bit(unsigned int nr, void * addr); +extern void ext2fs_fast_set_bit64(__u64 nr,void * addr); +extern void ext2fs_fast_clear_bit64(__u64 nr, void * addr); +extern __u16 ext2fs_swab16(__u16 val); +extern __u32 ext2fs_swab32(__u32 val); +extern __u64 ext2fs_swab64(__u64 val); + +extern int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block); +extern int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block); +extern int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block); + +extern int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode); +extern int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode); + +extern void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block); +extern void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block); +extern int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block); + +extern void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap); +extern ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap); +extern blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap); +extern ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap); + +extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); +extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); +extern int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); +#endif + +/* These functions routines moved to gen_bitmap.c */ +extern void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); +extern void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); +extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); +extern int ext2fs_test_inode_bitmap_range(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode, int num); +extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap, + __u32 bitno); +extern int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap, + blk_t bitno); +extern int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap, + blk_t bitno); +extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); +extern void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map); +extern __u32 ext2fs_get_generic_bitmap_start(ext2fs_generic_bitmap bitmap); +extern __u32 ext2fs_get_generic_bitmap_end(ext2fs_generic_bitmap bitmap); + +/* 64-bit versions */ + +#ifdef NO_INLINE_FUNCS +extern int ext2fs_mark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block); +extern int ext2fs_unmark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block); +extern int ext2fs_test_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block); + +extern int ext2fs_mark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern int ext2fs_unmark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern int ext2fs_test_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); + +extern void ext2fs_fast_mark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block); +extern void ext2fs_fast_unmark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block); +extern int ext2fs_fast_test_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block); + +extern void ext2fs_fast_mark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern void ext2fs_fast_unmark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern int ext2fs_fast_test_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern errcode_t ext2fs_find_first_zero_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t start, + blk64_t end, + blk64_t *out); +extern errcode_t ext2fs_find_first_zero_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t start, + ext2_ino_t end, + ext2_ino_t *out); +extern errcode_t ext2fs_find_first_set_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t start, + blk64_t end, + blk64_t *out); +extern errcode_t ext2fs_find_first_set_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t start, + ext2_ino_t end, + ext2_ino_t *out); +extern blk64_t ext2fs_get_block_bitmap_start2(ext2fs_block_bitmap bitmap); +extern ext2_ino_t ext2fs_get_inode_bitmap_start2(ext2fs_inode_bitmap bitmap); +extern blk64_t ext2fs_get_block_bitmap_end2(ext2fs_block_bitmap bitmap); +extern ext2_ino_t ext2fs_get_inode_bitmap_end2(ext2fs_inode_bitmap bitmap); + +extern int ext2fs_fast_test_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, + unsigned int num); +extern void ext2fs_fast_mark_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, + unsigned int num); +extern void ext2fs_fast_unmark_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, + unsigned int num); +#endif + +/* These routines moved to gen_bitmap64.c */ +extern void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap); +extern errcode_t ext2fs_compare_generic_bmap(errcode_t neq, + ext2fs_generic_bitmap bm1, + ext2fs_generic_bitmap bm2); +extern void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap); +extern int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap, + blk64_t bitno); +extern int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap, + blk64_t bitno); +extern int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap, + blk64_t bitno); +extern int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, unsigned int num); +extern __u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap bitmap); +extern __u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap bitmap); +extern int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, unsigned int num); +extern void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, unsigned int num); +extern void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, unsigned int num); +extern errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, + __u64 *out); +extern errcode_t ext2fs_find_first_set_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, + __u64 *out); + +/* + * The inline routines themselves... + * + * If NO_INLINE_FUNCS is defined, then we won't try to do inline + * functions at all; they will be included as normal functions in + * inline.c + */ +#ifdef NO_INLINE_FUNCS +#if (defined(__GNUC__) && (defined(__i386__) || defined(__i486__) || \ + defined(__i586__))) + /* This prevents bitops.c from trying to include the C */ + /* function version of these functions */ +#define _EXT2_HAVE_ASM_BITOPS_ +#endif +#endif /* NO_INLINE_FUNCS */ + +#if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS)) +#ifdef INCLUDE_INLINE_FUNCS +#if (__STDC_VERSION__ >= 199901L) +#define _INLINE_ extern inline +#else +#define _INLINE_ inline +#endif +#else /* !INCLUDE_INLINE FUNCS */ +#if (__STDC_VERSION__ >= 199901L) +#define _INLINE_ inline +#else /* not C99 */ +#ifdef __GNUC__ +#define _INLINE_ extern __inline__ +#else /* For Watcom C */ +#define _INLINE_ extern inline +#endif /* __GNUC__ */ +#endif /* __STDC_VERSION__ >= 199901L */ +#endif /* INCLUDE_INLINE_FUNCS */ + +/* + * Fast bit set/clear functions that doesn't need to return the + * previous bit value. + */ + +_INLINE_ void ext2fs_fast_set_bit(unsigned int nr,void * addr) +{ + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + *ADDR |= (unsigned char) (1 << (nr & 0x07)); +} + +_INLINE_ void ext2fs_fast_clear_bit(unsigned int nr, void * addr) +{ + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + *ADDR &= (unsigned char) ~(1 << (nr & 0x07)); +} + + +_INLINE_ void ext2fs_fast_set_bit64(__u64 nr, void * addr) +{ + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + *ADDR |= (unsigned char) (1 << (nr & 0x07)); +} + +_INLINE_ void ext2fs_fast_clear_bit64(__u64 nr, void * addr) +{ + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + *ADDR &= (unsigned char) ~(1 << (nr & 0x07)); +} + + +#if ((defined __GNUC__) && !defined(_EXT2_USE_C_VERSIONS_) && \ + (defined(__i386__) || defined(__i486__) || defined(__i586__))) + +#define _EXT2_HAVE_ASM_BITOPS_ +#define _EXT2_HAVE_ASM_SWAB_ + +/* + * These are done by inline assembly for speed reasons..... + * + * All bitoperations return 0 if the bit was cleared before the + * operation and != 0 if it was not. Bit 0 is the LSB of addr; bit 32 + * is the LSB of (addr+1). + */ + +/* + * Some hacks to defeat gcc over-optimizations.. + */ +struct __dummy_h { unsigned long a[100]; }; +#define EXT2FS_ADDR (*(struct __dummy_h *) addr) +#define EXT2FS_CONST_ADDR (*(const struct __dummy_h *) addr) + +_INLINE_ int ext2fs_set_bit(unsigned int nr, void * addr) +{ + int oldbit; + + addr = (void *) (((unsigned char *) addr) + (nr >> 3)); + __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"+m" (EXT2FS_ADDR) + :"r" (nr & 7)); + return oldbit; +} + +_INLINE_ int ext2fs_clear_bit(unsigned int nr, void * addr) +{ + int oldbit; + + addr = (void *) (((unsigned char *) addr) + (nr >> 3)); + __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"+m" (EXT2FS_ADDR) + :"r" (nr & 7)); + return oldbit; +} + +_INLINE_ int ext2fs_test_bit(unsigned int nr, const void * addr) +{ + int oldbit; + + addr = (const void *) (((const unsigned char *) addr) + (nr >> 3)); + __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit) + :"m" (EXT2FS_CONST_ADDR),"r" (nr & 7)); + return oldbit; +} + +_INLINE_ __u32 ext2fs_swab32(__u32 val) +{ +#ifdef EXT2FS_REQUIRE_486 + __asm__("bswap %0" : "=r" (val) : "0" (val)); +#else + __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ + "rorl $16,%0\n\t" /* swap words */ + "xchgb %b0,%h0" /* swap higher bytes */ + :"=q" (val) + : "0" (val)); +#endif + return val; +} + +_INLINE_ __u16 ext2fs_swab16(__u16 val) +{ + __asm__("xchgb %b0,%h0" /* swap bytes */ \ + : "=q" (val) \ + : "0" (val)); \ + return val; +} + +#undef EXT2FS_ADDR + +#endif /* i386 */ + + +#if !defined(_EXT2_HAVE_ASM_SWAB_) + +_INLINE_ __u16 ext2fs_swab16(__u16 val) +{ + return (val >> 8) | (__u16) (val << 8); +} + +_INLINE_ __u32 ext2fs_swab32(__u32 val) +{ + return ((val>>24) | ((val>>8)&0xFF00) | + ((val<<8)&0xFF0000) | (val<<24)); +} + +#endif /* !_EXT2_HAVE_ASM_SWAB */ + +_INLINE_ __u64 ext2fs_swab64(__u64 val) +{ + return (ext2fs_swab32((__u32) (val >> 32)) | + (((__u64)ext2fs_swab32(val & 0xFFFFFFFFUL)) << 32)); +} + +_INLINE_ int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block) +{ + return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, + block); +} + +_INLINE_ int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block) +{ + return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, + block); +} + +_INLINE_ int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block) +{ + return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, + block); +} + +_INLINE_ int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block) +{ + ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, block); +} + +_INLINE_ void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block) +{ + ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, block); +} + +_INLINE_ int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block) +{ + return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, + block); +} + +_INLINE_ void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, inode); +} + +_INLINE_ void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, inode); +} + +_INLINE_ int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap) +{ + return ext2fs_get_generic_bitmap_start((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap) +{ + return ext2fs_get_generic_bitmap_start((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap) +{ + return ext2fs_get_generic_bitmap_end((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap) +{ + return ext2fs_get_generic_bitmap_end((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num) +{ + return ext2fs_test_block_bitmap_range(bitmap, block, num); +} + +_INLINE_ void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num) +{ + ext2fs_mark_block_bitmap_range(bitmap, block, num); +} + +_INLINE_ void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num) +{ + ext2fs_unmark_block_bitmap_range(bitmap, block, num); +} + +/* 64-bit versions */ + +_INLINE_ int ext2fs_mark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block) +{ + return ext2fs_mark_generic_bmap((ext2fs_generic_bitmap) bitmap, + block); +} + +_INLINE_ int ext2fs_unmark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block) +{ + return ext2fs_unmark_generic_bmap((ext2fs_generic_bitmap) bitmap, block); +} + +_INLINE_ int ext2fs_test_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block) +{ + return ext2fs_test_generic_bmap((ext2fs_generic_bitmap) bitmap, + block); +} + +_INLINE_ int ext2fs_mark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_mark_generic_bmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ int ext2fs_unmark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_unmark_generic_bmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ int ext2fs_test_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_test_generic_bmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ void ext2fs_fast_mark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block) +{ + ext2fs_mark_generic_bmap((ext2fs_generic_bitmap) bitmap, block); +} + +_INLINE_ void ext2fs_fast_unmark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block) +{ + ext2fs_unmark_generic_bmap((ext2fs_generic_bitmap) bitmap, block); +} + +_INLINE_ int ext2fs_fast_test_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block) +{ + return ext2fs_test_generic_bmap((ext2fs_generic_bitmap) bitmap, + block); +} + +_INLINE_ void ext2fs_fast_mark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + ext2fs_mark_generic_bmap((ext2fs_generic_bitmap) bitmap, inode); +} + +_INLINE_ void ext2fs_fast_unmark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + ext2fs_unmark_generic_bmap((ext2fs_generic_bitmap) bitmap, inode); +} + +_INLINE_ int ext2fs_fast_test_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_test_generic_bmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ errcode_t ext2fs_find_first_zero_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t start, + blk64_t end, + blk64_t *out) +{ + __u64 o; + errcode_t rv; + + rv = ext2fs_find_first_zero_generic_bmap((ext2fs_generic_bitmap) bitmap, + start, end, &o); + if (!rv) + *out = o; + return rv; +} + +_INLINE_ errcode_t ext2fs_find_first_zero_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t start, + ext2_ino_t end, + ext2_ino_t *out) +{ + __u64 o; + errcode_t rv; + + rv = ext2fs_find_first_zero_generic_bmap((ext2fs_generic_bitmap) bitmap, + start, end, &o); + if (!rv) + *out = (ext2_ino_t) o; + return rv; +} + +_INLINE_ errcode_t ext2fs_find_first_set_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t start, + blk64_t end, + blk64_t *out) +{ + __u64 o; + errcode_t rv; + + rv = ext2fs_find_first_set_generic_bmap((ext2fs_generic_bitmap) bitmap, + start, end, &o); + if (!rv) + *out = o; + return rv; +} + +_INLINE_ errcode_t ext2fs_find_first_set_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t start, + ext2_ino_t end, + ext2_ino_t *out) +{ + __u64 o; + errcode_t rv; + + rv = ext2fs_find_first_set_generic_bmap((ext2fs_generic_bitmap) bitmap, + start, end, &o); + if (!rv) + *out = (ext2_ino_t) o; + return rv; +} + +_INLINE_ blk64_t ext2fs_get_block_bitmap_start2(ext2fs_block_bitmap bitmap) +{ + return ext2fs_get_generic_bmap_start((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_start2(ext2fs_inode_bitmap bitmap) +{ + return (ext2_ino_t) ext2fs_get_generic_bmap_start((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ blk64_t ext2fs_get_block_bitmap_end2(ext2fs_block_bitmap bitmap) +{ + return ext2fs_get_generic_bmap_end((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_end2(ext2fs_inode_bitmap bitmap) +{ + return (ext2_ino_t) ext2fs_get_generic_bmap_end((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ int ext2fs_fast_test_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, + unsigned int num) +{ + return ext2fs_test_block_bitmap_range2(bitmap, block, num); +} + +_INLINE_ void ext2fs_fast_mark_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, + unsigned int num) +{ + ext2fs_mark_block_bitmap_range2(bitmap, block, num); +} + +_INLINE_ void ext2fs_fast_unmark_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, + unsigned int num) +{ + ext2fs_unmark_block_bitmap_range2(bitmap, block, num); +} + +#undef _INLINE_ +#endif + +#ifndef _EXT2_HAVE_ASM_BITOPS_ +extern int ext2fs_set_bit(unsigned int nr,void * addr); +extern int ext2fs_clear_bit(unsigned int nr, void * addr); +extern int ext2fs_test_bit(unsigned int nr, const void * addr); +#endif + +extern int ext2fs_set_bit64(__u64 nr,void * addr); +extern int ext2fs_clear_bit64(__u64 nr, void * addr); +extern int ext2fs_test_bit64(__u64 nr, const void * addr); +extern unsigned int ext2fs_bitcount(const void *addr, unsigned int nbytes); diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libext2fs/ext2fs/ext2_err.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libext2fs/ext2fs/ext2_err.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,204 @@ +/* + * ext2_err.h: + * This file is automatically generated; please do not edit it. + */ + +#include + +#define EXT2_ET_BASE (2133571328L) +#define EXT2_ET_MAGIC_EXT2FS_FILSYS (2133571329L) +#define EXT2_ET_MAGIC_BADBLOCKS_LIST (2133571330L) +#define EXT2_ET_MAGIC_BADBLOCKS_ITERATE (2133571331L) +#define EXT2_ET_MAGIC_INODE_SCAN (2133571332L) +#define EXT2_ET_MAGIC_IO_CHANNEL (2133571333L) +#define EXT2_ET_MAGIC_UNIX_IO_CHANNEL (2133571334L) +#define EXT2_ET_MAGIC_IO_MANAGER (2133571335L) +#define EXT2_ET_MAGIC_BLOCK_BITMAP (2133571336L) +#define EXT2_ET_MAGIC_INODE_BITMAP (2133571337L) +#define EXT2_ET_MAGIC_GENERIC_BITMAP (2133571338L) +#define EXT2_ET_MAGIC_TEST_IO_CHANNEL (2133571339L) +#define EXT2_ET_MAGIC_DBLIST (2133571340L) +#define EXT2_ET_MAGIC_ICOUNT (2133571341L) +#define EXT2_ET_MAGIC_PQ_IO_CHANNEL (2133571342L) +#define EXT2_ET_MAGIC_EXT2_FILE (2133571343L) +#define EXT2_ET_MAGIC_E2IMAGE (2133571344L) +#define EXT2_ET_MAGIC_INODE_IO_CHANNEL (2133571345L) +#define EXT2_ET_MAGIC_EXTENT_HANDLE (2133571346L) +#define EXT2_ET_BAD_MAGIC (2133571347L) +#define EXT2_ET_REV_TOO_HIGH (2133571348L) +#define EXT2_ET_RO_FILSYS (2133571349L) +#define EXT2_ET_GDESC_READ (2133571350L) +#define EXT2_ET_GDESC_WRITE (2133571351L) +#define EXT2_ET_GDESC_BAD_BLOCK_MAP (2133571352L) +#define EXT2_ET_GDESC_BAD_INODE_MAP (2133571353L) +#define EXT2_ET_GDESC_BAD_INODE_TABLE (2133571354L) +#define EXT2_ET_INODE_BITMAP_WRITE (2133571355L) +#define EXT2_ET_INODE_BITMAP_READ (2133571356L) +#define EXT2_ET_BLOCK_BITMAP_WRITE (2133571357L) +#define EXT2_ET_BLOCK_BITMAP_READ (2133571358L) +#define EXT2_ET_INODE_TABLE_WRITE (2133571359L) +#define EXT2_ET_INODE_TABLE_READ (2133571360L) +#define EXT2_ET_NEXT_INODE_READ (2133571361L) +#define EXT2_ET_UNEXPECTED_BLOCK_SIZE (2133571362L) +#define EXT2_ET_DIR_CORRUPTED (2133571363L) +#define EXT2_ET_SHORT_READ (2133571364L) +#define EXT2_ET_SHORT_WRITE (2133571365L) +#define EXT2_ET_DIR_NO_SPACE (2133571366L) +#define EXT2_ET_NO_INODE_BITMAP (2133571367L) +#define EXT2_ET_NO_BLOCK_BITMAP (2133571368L) +#define EXT2_ET_BAD_INODE_NUM (2133571369L) +#define EXT2_ET_BAD_BLOCK_NUM (2133571370L) +#define EXT2_ET_EXPAND_DIR_ERR (2133571371L) +#define EXT2_ET_TOOSMALL (2133571372L) +#define EXT2_ET_BAD_BLOCK_MARK (2133571373L) +#define EXT2_ET_BAD_BLOCK_UNMARK (2133571374L) +#define EXT2_ET_BAD_BLOCK_TEST (2133571375L) +#define EXT2_ET_BAD_INODE_MARK (2133571376L) +#define EXT2_ET_BAD_INODE_UNMARK (2133571377L) +#define EXT2_ET_BAD_INODE_TEST (2133571378L) +#define EXT2_ET_FUDGE_BLOCK_BITMAP_END (2133571379L) +#define EXT2_ET_FUDGE_INODE_BITMAP_END (2133571380L) +#define EXT2_ET_BAD_IND_BLOCK (2133571381L) +#define EXT2_ET_BAD_DIND_BLOCK (2133571382L) +#define EXT2_ET_BAD_TIND_BLOCK (2133571383L) +#define EXT2_ET_NEQ_BLOCK_BITMAP (2133571384L) +#define EXT2_ET_NEQ_INODE_BITMAP (2133571385L) +#define EXT2_ET_BAD_DEVICE_NAME (2133571386L) +#define EXT2_ET_MISSING_INODE_TABLE (2133571387L) +#define EXT2_ET_CORRUPT_SUPERBLOCK (2133571388L) +#define EXT2_ET_BAD_GENERIC_MARK (2133571389L) +#define EXT2_ET_BAD_GENERIC_UNMARK (2133571390L) +#define EXT2_ET_BAD_GENERIC_TEST (2133571391L) +#define EXT2_ET_SYMLINK_LOOP (2133571392L) +#define EXT2_ET_CALLBACK_NOTHANDLED (2133571393L) +#define EXT2_ET_BAD_BLOCK_IN_INODE_TABLE (2133571394L) +#define EXT2_ET_UNSUPP_FEATURE (2133571395L) +#define EXT2_ET_RO_UNSUPP_FEATURE (2133571396L) +#define EXT2_ET_LLSEEK_FAILED (2133571397L) +#define EXT2_ET_NO_MEMORY (2133571398L) +#define EXT2_ET_INVALID_ARGUMENT (2133571399L) +#define EXT2_ET_BLOCK_ALLOC_FAIL (2133571400L) +#define EXT2_ET_INODE_ALLOC_FAIL (2133571401L) +#define EXT2_ET_NO_DIRECTORY (2133571402L) +#define EXT2_ET_TOO_MANY_REFS (2133571403L) +#define EXT2_ET_FILE_NOT_FOUND (2133571404L) +#define EXT2_ET_FILE_RO (2133571405L) +#define EXT2_ET_DB_NOT_FOUND (2133571406L) +#define EXT2_ET_DIR_EXISTS (2133571407L) +#define EXT2_ET_UNIMPLEMENTED (2133571408L) +#define EXT2_ET_CANCEL_REQUESTED (2133571409L) +#define EXT2_ET_FILE_TOO_BIG (2133571410L) +#define EXT2_ET_JOURNAL_NOT_BLOCK (2133571411L) +#define EXT2_ET_NO_JOURNAL_SB (2133571412L) +#define EXT2_ET_JOURNAL_TOO_SMALL (2133571413L) +#define EXT2_ET_JOURNAL_UNSUPP_VERSION (2133571414L) +#define EXT2_ET_LOAD_EXT_JOURNAL (2133571415L) +#define EXT2_ET_NO_JOURNAL (2133571416L) +#define EXT2_ET_DIRHASH_UNSUPP (2133571417L) +#define EXT2_ET_BAD_EA_BLOCK_NUM (2133571418L) +#define EXT2_ET_TOO_MANY_INODES (2133571419L) +#define EXT2_ET_NOT_IMAGE_FILE (2133571420L) +#define EXT2_ET_RES_GDT_BLOCKS (2133571421L) +#define EXT2_ET_RESIZE_INODE_CORRUPT (2133571422L) +#define EXT2_ET_SET_BMAP_NO_IND (2133571423L) +#define EXT2_ET_TDB_SUCCESS (2133571424L) +#define EXT2_ET_TDB_ERR_CORRUPT (2133571425L) +#define EXT2_ET_TDB_ERR_IO (2133571426L) +#define EXT2_ET_TDB_ERR_LOCK (2133571427L) +#define EXT2_ET_TDB_ERR_OOM (2133571428L) +#define EXT2_ET_TDB_ERR_EXISTS (2133571429L) +#define EXT2_ET_TDB_ERR_NOLOCK (2133571430L) +#define EXT2_ET_TDB_ERR_EINVAL (2133571431L) +#define EXT2_ET_TDB_ERR_NOEXIST (2133571432L) +#define EXT2_ET_TDB_ERR_RDONLY (2133571433L) +#define EXT2_ET_DBLIST_EMPTY (2133571434L) +#define EXT2_ET_RO_BLOCK_ITERATE (2133571435L) +#define EXT2_ET_MAGIC_EXTENT_PATH (2133571436L) +#define EXT2_ET_MAGIC_GENERIC_BITMAP64 (2133571437L) +#define EXT2_ET_MAGIC_BLOCK_BITMAP64 (2133571438L) +#define EXT2_ET_MAGIC_INODE_BITMAP64 (2133571439L) +#define EXT2_ET_MAGIC_RESERVED_13 (2133571440L) +#define EXT2_ET_MAGIC_RESERVED_14 (2133571441L) +#define EXT2_ET_MAGIC_RESERVED_15 (2133571442L) +#define EXT2_ET_MAGIC_RESERVED_16 (2133571443L) +#define EXT2_ET_MAGIC_RESERVED_17 (2133571444L) +#define EXT2_ET_MAGIC_RESERVED_18 (2133571445L) +#define EXT2_ET_MAGIC_RESERVED_19 (2133571446L) +#define EXT2_ET_EXTENT_HEADER_BAD (2133571447L) +#define EXT2_ET_EXTENT_INDEX_BAD (2133571448L) +#define EXT2_ET_EXTENT_LEAF_BAD (2133571449L) +#define EXT2_ET_EXTENT_NO_SPACE (2133571450L) +#define EXT2_ET_INODE_NOT_EXTENT (2133571451L) +#define EXT2_ET_EXTENT_NO_NEXT (2133571452L) +#define EXT2_ET_EXTENT_NO_PREV (2133571453L) +#define EXT2_ET_EXTENT_NO_UP (2133571454L) +#define EXT2_ET_EXTENT_NO_DOWN (2133571455L) +#define EXT2_ET_NO_CURRENT_NODE (2133571456L) +#define EXT2_ET_OP_NOT_SUPPORTED (2133571457L) +#define EXT2_ET_CANT_INSERT_EXTENT (2133571458L) +#define EXT2_ET_CANT_SPLIT_EXTENT (2133571459L) +#define EXT2_ET_EXTENT_NOT_FOUND (2133571460L) +#define EXT2_ET_EXTENT_NOT_SUPPORTED (2133571461L) +#define EXT2_ET_EXTENT_INVALID_LENGTH (2133571462L) +#define EXT2_ET_IO_CHANNEL_NO_SUPPORT_64 (2133571463L) +#define EXT2_ET_NO_MTAB_FILE (2133571464L) +#define EXT2_ET_CANT_USE_LEGACY_BITMAPS (2133571465L) +#define EXT2_ET_MMP_MAGIC_INVALID (2133571466L) +#define EXT2_ET_MMP_FAILED (2133571467L) +#define EXT2_ET_MMP_FSCK_ON (2133571468L) +#define EXT2_ET_MMP_BAD_BLOCK (2133571469L) +#define EXT2_ET_MMP_UNKNOWN_SEQ (2133571470L) +#define EXT2_ET_MMP_CHANGE_ABORT (2133571471L) +#define EXT2_ET_MMP_OPEN_DIRECT (2133571472L) +#define EXT2_ET_BAD_DESC_SIZE (2133571473L) +#define EXT2_ET_INODE_CSUM_INVALID (2133571474L) +#define EXT2_ET_INODE_BITMAP_CSUM_INVALID (2133571475L) +#define EXT2_ET_EXTENT_CSUM_INVALID (2133571476L) +#define EXT2_ET_DIR_NO_SPACE_FOR_CSUM (2133571477L) +#define EXT2_ET_DIR_CSUM_INVALID (2133571478L) +#define EXT2_ET_EXT_ATTR_CSUM_INVALID (2133571479L) +#define EXT2_ET_SB_CSUM_INVALID (2133571480L) +#define EXT2_ET_UNKNOWN_CSUM (2133571481L) +#define EXT2_ET_MMP_CSUM_INVALID (2133571482L) +#define EXT2_ET_FILE_EXISTS (2133571483L) +#define EXT2_ET_BLOCK_BITMAP_CSUM_INVALID (2133571484L) +#define EXT2_ET_INLINE_DATA_CANT_ITERATE (2133571485L) +#define EXT2_ET_EA_BAD_NAME_LEN (2133571486L) +#define EXT2_ET_EA_BAD_VALUE_SIZE (2133571487L) +#define EXT2_ET_BAD_EA_HASH (2133571488L) +#define EXT2_ET_BAD_EA_HEADER (2133571489L) +#define EXT2_ET_EA_KEY_NOT_FOUND (2133571490L) +#define EXT2_ET_EA_NO_SPACE (2133571491L) +#define EXT2_ET_MISSING_EA_FEATURE (2133571492L) +#define EXT2_ET_NO_INLINE_DATA (2133571493L) +#define EXT2_ET_INLINE_DATA_NO_BLOCK (2133571494L) +#define EXT2_ET_INLINE_DATA_NO_SPACE (2133571495L) +#define EXT2_ET_MAGIC_EA_HANDLE (2133571496L) +#define EXT2_ET_INODE_IS_GARBAGE (2133571497L) +#define EXT2_ET_EA_BAD_VALUE_OFFSET (2133571498L) +#define EXT2_ET_JOURNAL_FLAGS_WRONG (2133571499L) +#define EXT2_ET_UNDO_FILE_CORRUPT (2133571500L) +#define EXT2_ET_UNDO_FILE_WRONG (2133571501L) +#define EXT2_ET_FILESYSTEM_CORRUPTED (2133571502L) +#define EXT2_ET_BAD_CRC (2133571503L) +#define EXT2_ET_CORRUPT_JOURNAL_SB (2133571504L) +#define EXT2_ET_INODE_CORRUPTED (2133571505L) +#define EXT2_ET_EA_INODE_CORRUPTED (2133571506L) + +/* PAUL: Remove actual error functionality. */ + +#if 0 + +extern const struct error_table et_ext2_error_table; +extern void initialize_ext2_error_table(void); + +/* For compatibility with Heimdal */ +extern void initialize_ext2_error_table_r(struct et_list **list); + +#define ERROR_TABLE_BASE_ext2 (2133571328L) + +/* for compatibility with older versions... */ +#define init_ext2_err_tbl initialize_ext2_error_table +#define ext2_err_base ERROR_TABLE_BASE_ext2 + +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libext2fs/ext2fs/ext2_ext_attr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libext2fs/ext2fs/ext2_ext_attr.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,73 @@ +/* + File: linux/ext2_ext_attr.h + + On-disk format of extended attributes for the ext2 filesystem. + + (C) 2000 Andreas Gruenbacher, +*/ + +#ifndef _EXT2_EXT_ATTR_H +#define _EXT2_EXT_ATTR_H +/* Magic value in attribute blocks */ +#define EXT2_EXT_ATTR_MAGIC_v1 0xEA010000 +#define EXT2_EXT_ATTR_MAGIC 0xEA020000 + +/* Maximum number of references to one attribute block */ +#define EXT2_EXT_ATTR_REFCOUNT_MAX 1024 + +struct ext2_ext_attr_header { + __u32 h_magic; /* magic number for identification */ + __u32 h_refcount; /* reference count */ + __u32 h_blocks; /* number of disk blocks used */ + __u32 h_hash; /* hash value of all attributes */ + __u32 h_checksum; /* crc32c(uuid+id+xattrs) */ + /* id = inum if refcount = 1, else blknum */ + __u32 h_reserved[3]; /* zero right now */ +}; + +struct ext2_ext_attr_entry { + __u8 e_name_len; /* length of name */ + __u8 e_name_index; /* attribute name index */ + __u16 e_value_offs; /* offset in disk block of value */ + __u32 e_value_inum; /* inode in which the value is stored */ + __u32 e_value_size; /* size of attribute value */ + __u32 e_hash; /* hash value of name and value */ +#if 0 + char e_name[0]; /* attribute name */ +#endif +}; + +#define EXT2_EXT_ATTR_PAD_BITS 2 +#define EXT2_EXT_ATTR_PAD ((unsigned) 1<e_name_len)) ) +#define EXT2_EXT_ATTR_SIZE(size) \ + (((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND) +#define EXT2_EXT_IS_LAST_ENTRY(entry) (*((__u32 *)(entry)) == 0UL) +#define EXT2_EXT_ATTR_NAME(entry) \ + (((char *) (entry)) + sizeof(struct ext2_ext_attr_entry)) +#define EXT2_XATTR_LEN(name_len) \ + (((name_len) + EXT2_EXT_ATTR_ROUND + \ + sizeof(struct ext2_xattr_entry)) & ~EXT2_EXT_ATTR_ROUND) +#define EXT2_XATTR_SIZE(size) \ + (((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND) + +#ifdef __KERNEL__ +# ifdef CONFIG_EXT2_FS_EXT_ATTR +extern int ext2_get_ext_attr(struct inode *, const char *, char *, size_t, int); +extern int ext2_set_ext_attr(struct inode *, const char *, char *, size_t, int); +extern void ext2_ext_attr_free_inode(struct inode *inode); +extern void ext2_ext_attr_put_super(struct super_block *sb); +extern int ext2_ext_attr_init(void); +extern void ext2_ext_attr_done(void); +# else +# define ext2_get_ext_attr NULL +# define ext2_set_ext_attr NULL +# endif +#endif /* __KERNEL__ */ +#endif /* _EXT2_EXT_ATTR_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libext2fs/ext2fs/ext2_fs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libext2fs/ext2fs/ext2_fs.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,1119 @@ +/* + * linux/include/linux/ext2_fs.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_EXT2_FS_H +#define _LINUX_EXT2_FS_H + +#include /* Changed from linux/types.h */ + +#ifndef __GNUC_PREREQ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +#define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +#define __GNUC_PREREQ(maj, min) 0 +#endif +#endif + +/* + * The second extended filesystem constants/structures + */ + +/* + * Define EXT2FS_DEBUG to produce debug messages + */ +#undef EXT2FS_DEBUG + +/* + * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files + */ +#define EXT2_PREALLOCATE +#define EXT2_DEFAULT_PREALLOC_BLOCKS 8 + +/* + * The second extended file system version + */ +#define EXT2FS_DATE "95/08/09" +#define EXT2FS_VERSION "0.5b" + +/* + * Special inode numbers + */ +#define EXT2_BAD_INO 1 /* Bad blocks inode */ +#define EXT2_ROOT_INO 2 /* Root inode */ +#define EXT4_USR_QUOTA_INO 3 /* User quota inode */ +#define EXT4_GRP_QUOTA_INO 4 /* Group quota inode */ +#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ +#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ +#define EXT2_RESIZE_INO 7 /* Reserved group descriptors inode */ +#define EXT2_JOURNAL_INO 8 /* Journal inode */ +#define EXT2_EXCLUDE_INO 9 /* The "exclude" inode, for snapshots */ +#define EXT4_REPLICA_INO 10 /* Used by non-upstream feature */ + +/* First non-reserved inode for old ext2 filesystems */ +#define EXT2_GOOD_OLD_FIRST_INO 11 + +/* + * The second extended file system magic number + */ +#define EXT2_SUPER_MAGIC 0xEF53 + +#ifdef __KERNEL__ +#define EXT2_SB(sb) (&((sb)->u.ext2_sb)) +#else +/* Assume that user mode programs are passing in an ext2fs superblock, not + * a kernel struct super_block. This will allow us to call the feature-test + * macros from user land. */ +#define EXT2_SB(sb) (sb) +#endif + +/* + * Maximal count of links to a file + */ +#define EXT2_LINK_MAX 65000 + +/* + * Macro-instructions used to manage several block sizes + */ +#define EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */ +#define EXT2_MAX_BLOCK_LOG_SIZE 16 /* 65536 */ +#define EXT2_MIN_BLOCK_SIZE (1 << EXT2_MIN_BLOCK_LOG_SIZE) +#define EXT2_MAX_BLOCK_SIZE (1 << EXT2_MAX_BLOCK_LOG_SIZE) +#ifdef __KERNEL__ +#define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize) +#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) +#define EXT2_ADDR_PER_BLOCK_BITS(s) (EXT2_SB(s)->addr_per_block_bits) +#define EXT2_INODE_SIZE(s) (EXT2_SB(s)->s_inode_size) +#define EXT2_FIRST_INO(s) (EXT2_SB(s)->s_first_ino) +#else +#define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) +#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) +#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ + EXT2_GOOD_OLD_INODE_SIZE : (s)->s_inode_size) +#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ + EXT2_GOOD_OLD_FIRST_INO : (s)->s_first_ino) +#endif +#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof(__u32)) + +/* + * Macro-instructions used to manage allocation clusters + */ +#define EXT2_MIN_CLUSTER_LOG_SIZE EXT2_MIN_BLOCK_LOG_SIZE +#define EXT2_MAX_CLUSTER_LOG_SIZE 29 /* 512MB */ +#define EXT2_MIN_CLUSTER_SIZE EXT2_MIN_BLOCK_SIZE +#define EXT2_MAX_CLUSTER_SIZE (1 << EXT2_MAX_CLUSTER_LOG_SIZE) +#define EXT2_CLUSTER_SIZE(s) (EXT2_MIN_BLOCK_SIZE << \ + (s)->s_log_cluster_size) +#define EXT2_CLUSTER_SIZE_BITS(s) ((s)->s_log_cluster_size + 10) + +/* + * Macro-instructions used to manage fragments + * + * Note: for backwards compatibility only, for the dump program. + * Ext2/3/4 will never support fragments.... + */ +#define EXT2_MIN_FRAG_SIZE EXT2_MIN_BLOCK_SIZE +#define EXT2_MAX_FRAG_SIZE EXT2_MAX_BLOCK_SIZE +#define EXT2_MIN_FRAG_LOG_SIZE EXT2_MIN_BLOCK_LOG_SIZE +#define EXT2_FRAG_SIZE(s) EXT2_BLOCK_SIZE(s) +#define EXT2_FRAGS_PER_BLOCK(s) 1 + +/* + * ACL structures + */ +struct ext2_acl_header /* Header of Access Control Lists */ +{ + __u32 aclh_size; + __u32 aclh_file_count; + __u32 aclh_acle_count; + __u32 aclh_first_acle; +}; + +struct ext2_acl_entry /* Access Control List Entry */ +{ + __u32 acle_size; + __u16 acle_perms; /* Access permissions */ + __u16 acle_type; /* Type of entry */ + __u16 acle_tag; /* User or group identity */ + __u16 acle_pad1; + __u32 acle_next; /* Pointer on next entry for the */ + /* same inode or on next free entry */ +}; + +/* + * Structure of a blocks group descriptor + */ +struct ext2_group_desc +{ + __u32 bg_block_bitmap; /* Blocks bitmap block */ + __u32 bg_inode_bitmap; /* Inodes bitmap block */ + __u32 bg_inode_table; /* Inodes table block */ + __u16 bg_free_blocks_count; /* Free blocks count */ + __u16 bg_free_inodes_count; /* Free inodes count */ + __u16 bg_used_dirs_count; /* Directories count */ + __u16 bg_flags; + __u32 bg_exclude_bitmap_lo; /* Exclude bitmap for snapshots */ + __u16 bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */ + __u16 bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */ + __u16 bg_itable_unused; /* Unused inodes count */ + __u16 bg_checksum; /* crc16(s_uuid+group_num+group_desc)*/ +}; + +/* + * Structure of a blocks group descriptor + */ +struct ext4_group_desc +{ + __u32 bg_block_bitmap; /* Blocks bitmap block */ + __u32 bg_inode_bitmap; /* Inodes bitmap block */ + __u32 bg_inode_table; /* Inodes table block */ + __u16 bg_free_blocks_count; /* Free blocks count */ + __u16 bg_free_inodes_count; /* Free inodes count */ + __u16 bg_used_dirs_count; /* Directories count */ + __u16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */ + __u32 bg_exclude_bitmap_lo; /* Exclude bitmap for snapshots */ + __u16 bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */ + __u16 bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */ + __u16 bg_itable_unused; /* Unused inodes count */ + __u16 bg_checksum; /* crc16(sb_uuid+group+desc) */ + __u32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ + __u32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */ + __u32 bg_inode_table_hi; /* Inodes table block MSB */ + __u16 bg_free_blocks_count_hi;/* Free blocks count MSB */ + __u16 bg_free_inodes_count_hi;/* Free inodes count MSB */ + __u16 bg_used_dirs_count_hi; /* Directories count MSB */ + __u16 bg_itable_unused_hi; /* Unused inodes count MSB */ + __u32 bg_exclude_bitmap_hi; /* Exclude bitmap block MSB */ + __u16 bg_block_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bitmap) MSB */ + __u16 bg_inode_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bitmap) MSB */ + __u32 bg_reserved; +}; + +#define EXT4_BG_INODE_BITMAP_CSUM_HI_END \ + (offsetof(struct ext4_group_desc, bg_inode_bitmap_csum_hi) + \ + sizeof(__u16)) +#define EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION \ + (offsetof(struct ext4_group_desc, bg_block_bitmap_csum_hi) + \ + sizeof(__u16)) + +#define EXT2_BG_INODE_UNINIT 0x0001 /* Inode table/bitmap not initialized */ +#define EXT2_BG_BLOCK_UNINIT 0x0002 /* Block bitmap not initialized */ +#define EXT2_BG_INODE_ZEROED 0x0004 /* On-disk itable initialized to zero */ + +/* + * Data structures used by the directory indexing feature + * + * Note: all of the multibyte integer fields are little endian. + */ + +/* + * Note: dx_root_info is laid out so that if it should somehow get + * overlaid by a dirent the two low bits of the hash version will be + * zero. Therefore, the hash version mod 4 should never be 0. + * Sincerely, the paranoia department. + */ +struct ext2_dx_root_info { + __u32 reserved_zero; + __u8 hash_version; /* 0 now, 1 at release */ + __u8 info_length; /* 8 */ + __u8 indirect_levels; + __u8 unused_flags; +}; + +#define EXT2_HASH_LEGACY 0 +#define EXT2_HASH_HALF_MD4 1 +#define EXT2_HASH_TEA 2 +#define EXT2_HASH_LEGACY_UNSIGNED 3 /* reserved for userspace lib */ +#define EXT2_HASH_HALF_MD4_UNSIGNED 4 /* reserved for userspace lib */ +#define EXT2_HASH_TEA_UNSIGNED 5 /* reserved for userspace lib */ + +#define EXT2_HASH_FLAG_INCOMPAT 0x1 + +#define EXT4_DX_BLOCK_MASK 0x0fffffff + +struct ext2_dx_entry { + __le32 hash; + __le32 block; +}; + +struct ext2_dx_countlimit { + __le16 limit; + __le16 count; +}; + +/* + * This goes at the end of each htree block. + */ +struct ext2_dx_tail { + __le32 dt_reserved; + __le32 dt_checksum; /* crc32c(uuid+inum+dxblock) */ +}; + +/* + * Macro-instructions used to manage group descriptors + */ +#define EXT2_MIN_DESC_SIZE 32 +#define EXT2_MIN_DESC_SIZE_64BIT 64 +#define EXT2_MAX_DESC_SIZE EXT2_MIN_BLOCK_SIZE +#define EXT2_DESC_SIZE(s) \ + ((EXT2_SB(s)->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) ? \ + (s)->s_desc_size : EXT2_MIN_DESC_SIZE) + +#define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->s_blocks_per_group) +#define EXT2_INODES_PER_GROUP(s) (EXT2_SB(s)->s_inodes_per_group) +#define EXT2_CLUSTERS_PER_GROUP(s) (EXT2_SB(s)->s_clusters_per_group) +#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s)) +/* limits imposed by 16-bit value gd_free_{blocks,inode}_count */ +#define EXT2_MAX_BLOCKS_PER_GROUP(s) ((((unsigned) 1 << 16) - 8) * \ + (EXT2_CLUSTER_SIZE(s) / \ + EXT2_BLOCK_SIZE(s))) +#define EXT2_MAX_CLUSTERS_PER_GROUP(s) (((unsigned) 1 << 16) - 8) +#define EXT2_MAX_INODES_PER_GROUP(s) (((unsigned) 1 << 16) - \ + EXT2_INODES_PER_BLOCK(s)) +#ifdef __KERNEL__ +#define EXT2_DESC_PER_BLOCK(s) (EXT2_SB(s)->s_desc_per_block) +#define EXT2_DESC_PER_BLOCK_BITS(s) (EXT2_SB(s)->s_desc_per_block_bits) +#else +#define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_DESC_SIZE(s)) +#endif + +#define EXT2_GROUPS_TO_BLOCKS(s, g) ((blk64_t) EXT2_BLOCKS_PER_GROUP(s) * \ + (g)) +#define EXT2_GROUPS_TO_CLUSTERS(s, g) ((blk64_t) EXT2_CLUSTERS_PER_GROUP(s) * \ + (g)) + +/* + * Constants relative to the data blocks + */ +#define EXT2_NDIR_BLOCKS 12 +#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS +#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) +#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) +#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) + +/* + * Inode flags + */ +#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */ +#define EXT2_UNRM_FL 0x00000002 /* Undelete */ +#define EXT2_COMPR_FL 0x00000004 /* Compress file */ +#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */ +#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */ +#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */ +#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */ +/* Reserved for compression usage... */ +#define EXT2_DIRTY_FL 0x00000100 +#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ +#define EXT2_NOCOMPR_FL 0x00000400 /* Access raw compressed data */ + /* nb: was previously EXT2_ECOMPR_FL */ +#define EXT4_ENCRYPT_FL 0x00000800 /* encrypted inode */ +/* End compression flags --- maybe not all used */ +#define EXT2_BTREE_FL 0x00001000 /* btree format dir */ +#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */ +#define EXT2_IMAGIC_FL 0x00002000 +#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */ +#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */ +#define EXT2_DIRSYNC_FL 0x00010000 /* Synchronous directory modifications */ +#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ +#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ +#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ +#define EXT4_VERITY_FL 0x00100000 /* Verity protected inode */ +#define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */ +/* EXT4_EOFBLOCKS_FL 0x00400000 was here */ +#define FS_NOCOW_FL 0x00800000 /* Do not cow file */ +#define EXT4_SNAPFILE_FL 0x01000000 /* Inode is a snapshot */ +#define EXT4_SNAPFILE_DELETED_FL 0x04000000 /* Snapshot is being deleted */ +#define EXT4_SNAPFILE_SHRUNK_FL 0x08000000 /* Snapshot shrink has completed */ +#define EXT4_INLINE_DATA_FL 0x10000000 /* Inode has inline data */ +#define EXT4_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ +#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ + +#define EXT2_FL_USER_VISIBLE 0x204BDFFF /* User visible flags */ +#define EXT2_FL_USER_MODIFIABLE 0x204B80FF /* User modifiable flags */ + +/* + * ioctl commands + */ + +/* Used for online resize */ +struct ext2_new_group_input { + __u32 group; /* Group number for this data */ + __u32 block_bitmap; /* Absolute block number of block bitmap */ + __u32 inode_bitmap; /* Absolute block number of inode bitmap */ + __u32 inode_table; /* Absolute block number of inode table start */ + __u32 blocks_count; /* Total number of blocks in this group */ + __u16 reserved_blocks; /* Number of reserved blocks in this group */ + __u16 unused; /* Number of reserved GDT blocks in group */ +}; + +struct ext4_new_group_input { + __u32 group; /* Group number for this data */ + __u64 block_bitmap; /* Absolute block number of block bitmap */ + __u64 inode_bitmap; /* Absolute block number of inode bitmap */ + __u64 inode_table; /* Absolute block number of inode table start */ + __u32 blocks_count; /* Total number of blocks in this group */ + __u16 reserved_blocks; /* Number of reserved blocks in this group */ + __u16 unused; +}; + +#ifdef __GNU__ /* Needed for the Hurd */ +#define _IOT_ext2_new_group_input _IOT (_IOTS(__u32), 5, _IOTS(__u16), 2, 0, 0) +#endif + +#define EXT2_IOC_GETFLAGS _IOR('f', 1, long) +#define EXT2_IOC_SETFLAGS _IOW('f', 2, long) +#define EXT2_IOC_GETVERSION _IOR('v', 1, long) +#define EXT2_IOC_SETVERSION _IOW('v', 2, long) +#define EXT2_IOC_GETVERSION_NEW _IOR('f', 3, long) +#define EXT2_IOC_SETVERSION_NEW _IOW('f', 4, long) +#define EXT2_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) +#define EXT2_IOC_GROUP_ADD _IOW('f', 8,struct ext2_new_group_input) +#define EXT4_IOC_GROUP_ADD _IOW('f', 8,struct ext4_new_group_input) +#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64) + +/* + * Structure of an inode on the disk + */ +struct ext2_inode { +/*00*/ __u16 i_mode; /* File mode */ + __u16 i_uid; /* Low 16 bits of Owner Uid */ + __u32 i_size; /* Size in bytes */ + __u32 i_atime; /* Access time */ + __u32 i_ctime; /* Inode change time */ +/*10*/ __u32 i_mtime; /* Modification time */ + __u32 i_dtime; /* Deletion Time */ + __u16 i_gid; /* Low 16 bits of Group Id */ + __u16 i_links_count; /* Links count */ + __u32 i_blocks; /* Blocks count */ +/*20*/ __u32 i_flags; /* File flags */ + union { + struct { + __u32 l_i_version; /* was l_i_reserved1 */ + } linux1; + struct { + __u32 h_i_translator; + } hurd1; + } osd1; /* OS dependent 1 */ +/*28*/ __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ +/*64*/ __u32 i_generation; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ + __u32 i_size_high; +/*70*/ __u32 i_faddr; /* Fragment address */ + union { + struct { + __u16 l_i_blocks_hi; + __u16 l_i_file_acl_high; + __u16 l_i_uid_high; /* these 2 fields */ + __u16 l_i_gid_high; /* were reserved2[0] */ + __u16 l_i_checksum_lo; /* crc32c(uuid+inum+inode) */ + __u16 l_i_reserved; + } linux2; + struct { + __u8 h_i_frag; /* Fragment number */ + __u8 h_i_fsize; /* Fragment size */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; + __u32 h_i_author; + } hurd2; + } osd2; /* OS dependent 2 */ +}; + +/* + * Permanent part of an large inode on the disk + */ +struct ext2_inode_large { +/*00*/ __u16 i_mode; /* File mode */ + __u16 i_uid; /* Low 16 bits of Owner Uid */ + __u32 i_size; /* Size in bytes */ + __u32 i_atime; /* Access time */ + __u32 i_ctime; /* Inode Change time */ +/*10*/ __u32 i_mtime; /* Modification time */ + __u32 i_dtime; /* Deletion Time */ + __u16 i_gid; /* Low 16 bits of Group Id */ + __u16 i_links_count; /* Links count */ + __u32 i_blocks; /* Blocks count */ +/*20*/ __u32 i_flags; /* File flags */ + union { + struct { + __u32 l_i_version; /* was l_i_reserved1 */ + } linux1; + struct { + __u32 h_i_translator; + } hurd1; + } osd1; /* OS dependent 1 */ +/*28*/ __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ +/*64*/ __u32 i_generation; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ + __u32 i_size_high; +/*70*/ __u32 i_faddr; /* Fragment address */ + union { + struct { + __u16 l_i_blocks_hi; + __u16 l_i_file_acl_high; + __u16 l_i_uid_high; /* these 2 fields */ + __u16 l_i_gid_high; /* were reserved2[0] */ + __u16 l_i_checksum_lo; /* crc32c(uuid+inum+inode) */ + __u16 l_i_reserved; + } linux2; + struct { + __u8 h_i_frag; /* Fragment number */ + __u8 h_i_fsize; /* Fragment size */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; + __u32 h_i_author; + } hurd2; + } osd2; /* OS dependent 2 */ +/*80*/ __u16 i_extra_isize; + __u16 i_checksum_hi; /* crc32c(uuid+inum+inode) */ + __u32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */ + __u32 i_mtime_extra; /* extra Modification time (nsec << 2 | epoch) */ + __u32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */ +/*90*/ __u32 i_crtime; /* File creation time */ + __u32 i_crtime_extra; /* extra File creation time (nsec << 2 | epoch)*/ + __u32 i_version_hi; /* high 32 bits for 64-bit version */ +/*9c*/ __u32 i_projid; /* Project ID */ +}; + +#define EXT4_INODE_CSUM_HI_EXTRA_END \ + (offsetof(struct ext2_inode_large, i_checksum_hi) + sizeof(__u16) - \ + EXT2_GOOD_OLD_INODE_SIZE) + +#define EXT4_EPOCH_BITS 2 +#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1) + +#define i_checksum_lo osd2.linux2.l_i_checksum_lo + +#define inode_includes(size, field) \ + (size >= (sizeof(((struct ext2_inode_large *)0)->field) + \ + offsetof(struct ext2_inode_large, field))) + +#if defined(__KERNEL__) || defined(__linux__) +#define i_reserved1 osd1.linux1.l_i_reserved1 +#define i_frag osd2.linux2.l_i_frag +#define i_fsize osd2.linux2.l_i_fsize +#define i_uid_low i_uid +#define i_gid_low i_gid +#define i_uid_high osd2.linux2.l_i_uid_high +#define i_gid_high osd2.linux2.l_i_gid_high +#else +#if defined(__GNU__) + +#define i_translator osd1.hurd1.h_i_translator +#define i_frag osd2.hurd2.h_i_frag; +#define i_fsize osd2.hurd2.h_i_fsize; +#define i_uid_high osd2.hurd2.h_i_uid_high +#define i_gid_high osd2.hurd2.h_i_gid_high +#define i_author osd2.hurd2.h_i_author + +#endif /* __GNU__ */ +#endif /* defined(__KERNEL__) || defined(__linux__) */ + +#define inode_uid(inode) ((inode).i_uid | (inode).osd2.linux2.l_i_uid_high << 16) +#define inode_gid(inode) ((inode).i_gid | (inode).osd2.linux2.l_i_gid_high << 16) +#define inode_projid(inode) ((inode).i_projid) +#define ext2fs_set_i_uid_high(inode,x) ((inode).osd2.linux2.l_i_uid_high = (x)) +#define ext2fs_set_i_gid_high(inode,x) ((inode).osd2.linux2.l_i_gid_high = (x)) + +static inline +struct ext2_inode *EXT2_INODE(struct ext2_inode_large *large_inode) +{ + return (struct ext2_inode *) large_inode; +} + +/* + * File system states + */ +#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */ +#define EXT2_ERROR_FS 0x0002 /* Errors detected */ +#define EXT3_ORPHAN_FS 0x0004 /* Orphans being recovered */ + +/* + * Misc. filesystem flags + */ +#define EXT2_FLAGS_SIGNED_HASH 0x0001 /* Signed dirhash in use */ +#define EXT2_FLAGS_UNSIGNED_HASH 0x0002 /* Unsigned dirhash in use */ +#define EXT2_FLAGS_TEST_FILESYS 0x0004 /* OK for use on development code */ +#define EXT2_FLAGS_IS_SNAPSHOT 0x0010 /* This is a snapshot image */ +#define EXT2_FLAGS_FIX_SNAPSHOT 0x0020 /* Snapshot inodes corrupted */ +#define EXT2_FLAGS_FIX_EXCLUDE 0x0040 /* Exclude bitmaps corrupted */ + +/* + * Mount flags + */ +#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */ +#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */ +#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */ +#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ +#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */ +#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ +#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ +#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */ + +#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt +#define set_opt(o, opt) o |= EXT2_MOUNT_##opt +#define test_opt(sb, opt) (EXT2_SB(sb)->s_mount_opt & \ + EXT2_MOUNT_##opt) +/* + * Maximal mount counts between two filesystem checks + */ +#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ +#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */ + +/* + * Behaviour when detecting errors + */ +#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */ +#define EXT2_ERRORS_RO 2 /* Remount fs read-only */ +#define EXT2_ERRORS_PANIC 3 /* Panic */ +#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE + +#if (__GNUC__ >= 4) +#define ext4_offsetof(TYPE,MEMBER) __builtin_offsetof(TYPE,MEMBER) +#else +#define ext4_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +/* Metadata checksum algorithms */ +#define EXT2_CRC32C_CHKSUM 1 + +/* Encryption algorithms, key size and key reference len */ +#define EXT4_ENCRYPTION_MODE_INVALID 0 +#define EXT4_ENCRYPTION_MODE_AES_256_XTS 1 +#define EXT4_ENCRYPTION_MODE_AES_256_GCM 2 +#define EXT4_ENCRYPTION_MODE_AES_256_CBC 3 +#define EXT4_ENCRYPTION_MODE_AES_256_CTS 4 + +#define EXT4_AES_256_XTS_KEY_SIZE 64 +#define EXT4_AES_256_GCM_KEY_SIZE 32 +#define EXT4_AES_256_CBC_KEY_SIZE 32 +#define EXT4_AES_256_CTS_KEY_SIZE 32 +#define EXT4_MAX_KEY_SIZE 64 + +#define EXT4_KEY_DESCRIPTOR_SIZE 8 +#define EXT4_CRYPTO_BLOCK_SIZE 16 + +/* Password derivation constants */ +#define EXT4_MAX_PASSPHRASE_SIZE 1024 +#define EXT4_MAX_SALT_SIZE 256 +#define EXT4_PBKDF2_ITERATIONS 0xFFFF + +#define EXT2_LABEL_LEN 16 + +/* + * Policy provided via an ioctl on the topmost directory. This + * structure is also in the kernel. + */ +struct ext4_encryption_policy { + char version; + char contents_encryption_mode; + char filenames_encryption_mode; + char flags; + char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE]; +} __attribute__((__packed__)); + +struct ext4_encryption_key { + __u32 mode; + char raw[EXT4_MAX_KEY_SIZE]; + __u32 size; +} __attribute__((__packed__)); + +/* + * Structure of the super block + */ +struct ext2_super_block { +/*000*/ __u32 s_inodes_count; /* Inodes count */ + __u32 s_blocks_count; /* Blocks count */ + __u32 s_r_blocks_count; /* Reserved blocks count */ + __u32 s_free_blocks_count; /* Free blocks count */ +/*010*/ __u32 s_free_inodes_count; /* Free inodes count */ + __u32 s_first_data_block; /* First Data Block */ + __u32 s_log_block_size; /* Block size */ + __u32 s_log_cluster_size; /* Allocation cluster size */ +/*020*/ __u32 s_blocks_per_group; /* # Blocks per group */ + __u32 s_clusters_per_group; /* # Fragments per group */ + __u32 s_inodes_per_group; /* # Inodes per group */ + __u32 s_mtime; /* Mount time */ +/*030*/ __u32 s_wtime; /* Write time */ + __u16 s_mnt_count; /* Mount count */ + __s16 s_max_mnt_count; /* Maximal mount count */ + __u16 s_magic; /* Magic signature */ + __u16 s_state; /* File system state */ + __u16 s_errors; /* Behaviour when detecting errors */ + __u16 s_minor_rev_level; /* minor revision level */ +/*040*/ __u32 s_lastcheck; /* time of last check */ + __u32 s_checkinterval; /* max. time between checks */ + __u32 s_creator_os; /* OS */ + __u32 s_rev_level; /* Revision level */ +/*050*/ __u16 s_def_resuid; /* Default uid for reserved blocks */ + __u16 s_def_resgid; /* Default gid for reserved blocks */ + /* + * These fields are for EXT2_DYNAMIC_REV superblocks only. + * + * Note: the difference between the compatible feature set and + * the incompatible feature set is that if there is a bit set + * in the incompatible feature set that the kernel doesn't + * know about, it should refuse to mount the filesystem. + * + * e2fsck's requirements are more strict; if it doesn't know + * about a feature in either the compatible or incompatible + * feature set, it must abort and not try to meddle with + * things it doesn't understand... + */ + __u32 s_first_ino; /* First non-reserved inode */ + __u16 s_inode_size; /* size of inode structure */ + __u16 s_block_group_nr; /* block group # of this superblock */ + __u32 s_feature_compat; /* compatible feature set */ +/*060*/ __u32 s_feature_incompat; /* incompatible feature set */ + __u32 s_feature_ro_compat; /* readonly-compatible feature set */ +/*068*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */ +/*078*/ char s_volume_name[EXT2_LABEL_LEN]; /* volume name */ +/*088*/ char s_last_mounted[64]; /* directory where last mounted */ +/*0c8*/ __u32 s_algorithm_usage_bitmap; /* For compression */ + /* + * Performance hints. Directory preallocation should only + * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on. + */ + __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + __u16 s_reserved_gdt_blocks; /* Per group table for online growth */ + /* + * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set. + */ +/*0d0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */ +/*0e0*/ __u32 s_journal_inum; /* inode number of journal file */ + __u32 s_journal_dev; /* device number of journal file */ + __u32 s_last_orphan; /* start of list of inodes to delete */ +/*0ec*/ __u32 s_hash_seed[4]; /* HTREE hash seed */ +/*0fc*/ __u8 s_def_hash_version; /* Default hash version to use */ + __u8 s_jnl_backup_type; /* Default type of journal backup */ + __u16 s_desc_size; /* Group desc. size: INCOMPAT_64BIT */ +/*100*/ __u32 s_default_mount_opts; /* default EXT2_MOUNT_* flags used */ + __u32 s_first_meta_bg; /* First metablock group */ + __u32 s_mkfs_time; /* When the filesystem was created */ +/*10c*/ __u32 s_jnl_blocks[17]; /* Backup of the journal inode */ +/*150*/ __u32 s_blocks_count_hi; /* Blocks count high 32bits */ + __u32 s_r_blocks_count_hi; /* Reserved blocks count high 32 bits*/ + __u32 s_free_blocks_hi; /* Free blocks count */ + __u16 s_min_extra_isize; /* All inodes have at least # bytes */ + __u16 s_want_extra_isize; /* New inodes should reserve # bytes */ +/*160*/ __u32 s_flags; /* Miscellaneous flags */ + __u16 s_raid_stride; /* RAID stride in blocks */ + __u16 s_mmp_update_interval; /* # seconds to wait in MMP checking */ + __u64 s_mmp_block; /* Block for multi-mount protection */ +/*170*/ __u32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/ + __u8 s_log_groups_per_flex; /* FLEX_BG group size */ + __u8 s_checksum_type; /* metadata checksum algorithm */ + __u8 s_encryption_level; /* versioning level for encryption */ + __u8 s_reserved_pad; /* Padding to next 32bits */ + __u64 s_kbytes_written; /* nr of lifetime kilobytes written */ +/*180*/ __u32 s_snapshot_inum; /* Inode number of active snapshot */ + __u32 s_snapshot_id; /* sequential ID of active snapshot */ + __u64 s_snapshot_r_blocks_count; /* active snapshot reserved blocks */ +/*190*/ __u32 s_snapshot_list; /* inode number of disk snapshot list */ +#define EXT4_S_ERR_START ext4_offsetof(struct ext2_super_block, s_error_count) + __u32 s_error_count; /* number of fs errors */ + __u32 s_first_error_time; /* first time an error happened */ + __u32 s_first_error_ino; /* inode involved in first error */ +/*1a0*/ __u64 s_first_error_block; /* block involved in first error */ + __u8 s_first_error_func[32]; /* function where the error happened */ +/*1c8*/ __u32 s_first_error_line; /* line number where error happened */ + __u32 s_last_error_time; /* most recent time of an error */ +/*1d0*/ __u32 s_last_error_ino; /* inode involved in last error */ + __u32 s_last_error_line; /* line number where error happened */ + __u64 s_last_error_block; /* block involved of last error */ +/*1e0*/ __u8 s_last_error_func[32]; /* function where the error happened */ +#define EXT4_S_ERR_END ext4_offsetof(struct ext2_super_block, s_mount_opts) +/*200*/ __u8 s_mount_opts[64]; +/*240*/ __u32 s_usr_quota_inum; /* inode number of user quota file */ + __u32 s_grp_quota_inum; /* inode number of group quota file */ + __u32 s_overhead_blocks; /* overhead blocks/clusters in fs */ +/*24c*/ __u32 s_backup_bgs[2]; /* If sparse_super2 enabled */ +/*254*/ __u8 s_encrypt_algos[4]; /* Encryption algorithms in use */ +/*258*/ __u8 s_encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ +/*268*/ __le32 s_lpf_ino; /* Location of the lost+found inode */ + __le32 s_prj_quota_inum; /* inode for tracking project quota */ +/*270*/ __le32 s_checksum_seed; /* crc32c(orig_uuid) if csum_seed set */ + __le32 s_reserved[98]; /* Padding to the end of the block */ +/*3fc*/ __u32 s_checksum; /* crc32c(superblock) */ +}; + +#define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START) + +/* + * Codes for operating systems + */ +#define EXT2_OS_LINUX 0 +#define EXT2_OS_HURD 1 +#define EXT2_OBSO_OS_MASIX 2 +#define EXT2_OS_FREEBSD 3 +#define EXT2_OS_LITES 4 + +/* + * Revision levels + */ +#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ +#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ + +#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV +#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV + +#define EXT2_GOOD_OLD_INODE_SIZE 128 + +/* + * Journal inode backup types + */ +#define EXT3_JNL_BACKUP_BLOCKS 1 + +/* + * Feature set definitions + */ + +#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_feature_compat & (mask) ) +#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_feature_ro_compat & (mask) ) +#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_feature_incompat & (mask) ) + +#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 +#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002 +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 +#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008 +#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010 +#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020 +#define EXT2_FEATURE_COMPAT_LAZY_BG 0x0040 +/* #define EXT2_FEATURE_COMPAT_EXCLUDE_INODE 0x0080 not used, legacy */ +#define EXT2_FEATURE_COMPAT_EXCLUDE_BITMAP 0x0100 +#define EXT4_FEATURE_COMPAT_SPARSE_SUPER2 0x0200 + + +#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +/* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 not used */ +#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008 +#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 +#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020 +#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 +#define EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT 0x0080 +#define EXT4_FEATURE_RO_COMPAT_QUOTA 0x0100 +#define EXT4_FEATURE_RO_COMPAT_BIGALLOC 0x0200 +/* + * METADATA_CSUM implies GDT_CSUM. When METADATA_CSUM is set, group + * descriptor checksums use the same algorithm as all other data + * structures' checksums. + */ +#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400 +#define EXT4_FEATURE_RO_COMPAT_REPLICA 0x0800 +#define EXT4_FEATURE_RO_COMPAT_READONLY 0x1000 +#define EXT4_FEATURE_RO_COMPAT_PROJECT 0x2000 /* Project quota */ +#define EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS 0x4000 +#define EXT4_FEATURE_RO_COMPAT_VERITY 0x8000 + +#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ +#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 +#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040 +#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 +#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 +#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 +#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400 +#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 +#define EXT4_FEATURE_INCOMPAT_CSUM_SEED 0x2000 +#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */ +#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */ +#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000 + +#define EXT4_FEATURE_COMPAT_FUNCS(name, ver, flagname) \ +static inline int ext2fs_has_feature_##name(struct ext2_super_block *sb) \ +{ \ + return ((EXT2_SB(sb)->s_feature_compat & \ + EXT##ver##_FEATURE_COMPAT_##flagname) != 0); \ +} \ +static inline void ext2fs_set_feature_##name(struct ext2_super_block *sb) \ +{ \ + EXT2_SB(sb)->s_feature_compat |= \ + EXT##ver##_FEATURE_COMPAT_##flagname; \ +} \ +static inline void ext2fs_clear_feature_##name(struct ext2_super_block *sb) \ +{ \ + EXT2_SB(sb)->s_feature_compat &= \ + ~EXT##ver##_FEATURE_COMPAT_##flagname; \ +} + +#define EXT4_FEATURE_RO_COMPAT_FUNCS(name, ver, flagname) \ +static inline int ext2fs_has_feature_##name(struct ext2_super_block *sb) \ +{ \ + return ((EXT2_SB(sb)->s_feature_ro_compat & \ + EXT##ver##_FEATURE_RO_COMPAT_##flagname) != 0); \ +} \ +static inline void ext2fs_set_feature_##name(struct ext2_super_block *sb) \ +{ \ + EXT2_SB(sb)->s_feature_ro_compat |= \ + EXT##ver##_FEATURE_RO_COMPAT_##flagname; \ +} \ +static inline void ext2fs_clear_feature_##name(struct ext2_super_block *sb) \ +{ \ + EXT2_SB(sb)->s_feature_ro_compat &= \ + ~EXT##ver##_FEATURE_RO_COMPAT_##flagname; \ +} + +#define EXT4_FEATURE_INCOMPAT_FUNCS(name, ver, flagname) \ +static inline int ext2fs_has_feature_##name(struct ext2_super_block *sb) \ +{ \ + return ((EXT2_SB(sb)->s_feature_incompat & \ + EXT##ver##_FEATURE_INCOMPAT_##flagname) != 0); \ +} \ +static inline void ext2fs_set_feature_##name(struct ext2_super_block *sb) \ +{ \ + EXT2_SB(sb)->s_feature_incompat |= \ + EXT##ver##_FEATURE_INCOMPAT_##flagname; \ +} \ +static inline void ext2fs_clear_feature_##name(struct ext2_super_block *sb) \ +{ \ + EXT2_SB(sb)->s_feature_incompat &= \ + ~EXT##ver##_FEATURE_INCOMPAT_##flagname; \ +} + +EXT4_FEATURE_COMPAT_FUNCS(dir_prealloc, 2, DIR_PREALLOC) +EXT4_FEATURE_COMPAT_FUNCS(imagic_inodes, 2, IMAGIC_INODES) +EXT4_FEATURE_COMPAT_FUNCS(journal, 3, HAS_JOURNAL) +EXT4_FEATURE_COMPAT_FUNCS(xattr, 2, EXT_ATTR) +EXT4_FEATURE_COMPAT_FUNCS(resize_inode, 2, RESIZE_INODE) +EXT4_FEATURE_COMPAT_FUNCS(dir_index, 2, DIR_INDEX) +EXT4_FEATURE_COMPAT_FUNCS(lazy_bg, 2, LAZY_BG) +EXT4_FEATURE_COMPAT_FUNCS(exclude_bitmap, 2, EXCLUDE_BITMAP) +EXT4_FEATURE_COMPAT_FUNCS(sparse_super2, 4, SPARSE_SUPER2) + +EXT4_FEATURE_RO_COMPAT_FUNCS(sparse_super, 2, SPARSE_SUPER) +EXT4_FEATURE_RO_COMPAT_FUNCS(large_file, 2, LARGE_FILE) +EXT4_FEATURE_RO_COMPAT_FUNCS(huge_file, 4, HUGE_FILE) +EXT4_FEATURE_RO_COMPAT_FUNCS(gdt_csum, 4, GDT_CSUM) +EXT4_FEATURE_RO_COMPAT_FUNCS(dir_nlink, 4, DIR_NLINK) +EXT4_FEATURE_RO_COMPAT_FUNCS(extra_isize, 4, EXTRA_ISIZE) +EXT4_FEATURE_RO_COMPAT_FUNCS(has_snapshot, 4, HAS_SNAPSHOT) +EXT4_FEATURE_RO_COMPAT_FUNCS(quota, 4, QUOTA) +EXT4_FEATURE_RO_COMPAT_FUNCS(bigalloc, 4, BIGALLOC) +EXT4_FEATURE_RO_COMPAT_FUNCS(metadata_csum, 4, METADATA_CSUM) +EXT4_FEATURE_RO_COMPAT_FUNCS(replica, 4, REPLICA) +EXT4_FEATURE_RO_COMPAT_FUNCS(readonly, 4, READONLY) +EXT4_FEATURE_RO_COMPAT_FUNCS(project, 4, PROJECT) +EXT4_FEATURE_RO_COMPAT_FUNCS(shared_blocks, 4, SHARED_BLOCKS) +EXT4_FEATURE_RO_COMPAT_FUNCS(verity, 4, VERITY) + +EXT4_FEATURE_INCOMPAT_FUNCS(compression, 2, COMPRESSION) +EXT4_FEATURE_INCOMPAT_FUNCS(filetype, 2, FILETYPE) +EXT4_FEATURE_INCOMPAT_FUNCS(journal_needs_recovery, 3, RECOVER) +EXT4_FEATURE_INCOMPAT_FUNCS(journal_dev, 3, JOURNAL_DEV) +EXT4_FEATURE_INCOMPAT_FUNCS(meta_bg, 2, META_BG) +EXT4_FEATURE_INCOMPAT_FUNCS(extents, 3, EXTENTS) +EXT4_FEATURE_INCOMPAT_FUNCS(64bit, 4, 64BIT) +EXT4_FEATURE_INCOMPAT_FUNCS(mmp, 4, MMP) +EXT4_FEATURE_INCOMPAT_FUNCS(flex_bg, 4, FLEX_BG) +EXT4_FEATURE_INCOMPAT_FUNCS(ea_inode, 4, EA_INODE) +EXT4_FEATURE_INCOMPAT_FUNCS(dirdata, 4, DIRDATA) +EXT4_FEATURE_INCOMPAT_FUNCS(csum_seed, 4, CSUM_SEED) +EXT4_FEATURE_INCOMPAT_FUNCS(largedir, 4, LARGEDIR) +EXT4_FEATURE_INCOMPAT_FUNCS(inline_data, 4, INLINE_DATA) +EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, 4, ENCRYPT) + +#define EXT2_FEATURE_COMPAT_SUPP 0 +#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ + EXT4_FEATURE_INCOMPAT_MMP| \ + EXT4_FEATURE_INCOMPAT_LARGEDIR| \ + EXT4_FEATURE_INCOMPAT_EA_INODE) +#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \ + EXT2_FEATURE_RO_COMPAT_BTREE_DIR| \ + EXT4_FEATURE_RO_COMPAT_VERITY) + +/* + * Default values for user and/or group using reserved blocks + */ +#define EXT2_DEF_RESUID 0 +#define EXT2_DEF_RESGID 0 + +/* + * Default mount options + */ +#define EXT2_DEFM_DEBUG 0x0001 +#define EXT2_DEFM_BSDGROUPS 0x0002 +#define EXT2_DEFM_XATTR_USER 0x0004 +#define EXT2_DEFM_ACL 0x0008 +#define EXT2_DEFM_UID16 0x0010 +#define EXT3_DEFM_JMODE 0x0060 +#define EXT3_DEFM_JMODE_DATA 0x0020 +#define EXT3_DEFM_JMODE_ORDERED 0x0040 +#define EXT3_DEFM_JMODE_WBACK 0x0060 +#define EXT4_DEFM_NOBARRIER 0x0100 +#define EXT4_DEFM_BLOCK_VALIDITY 0x0200 +#define EXT4_DEFM_DISCARD 0x0400 +#define EXT4_DEFM_NODELALLOC 0x0800 + +/* + * Structure of a directory entry + */ +#define EXT2_NAME_LEN 255 + +struct ext2_dir_entry { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u16 name_len; /* Name length */ + char name[EXT2_NAME_LEN]; /* File name */ +}; + +/* + * The new version of the directory entry. Since EXT2 structures are + * stored in intel byte order, and the name_len field could never be + * bigger than 255 chars, it's safe to reclaim the extra byte for the + * file_type field. + * + * This structure is deprecated due to endian issues. Please use struct + * ext2_dir_entry and accessor functions + * ext2fs_dirent_name_len + * ext2fs_dirent_set_name_len + * ext2fs_dirent_file_type + * ext2fs_dirent_set_file_type + * to get and set name_len and file_type fields. + */ +struct ext2_dir_entry_2 { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u8 name_len; /* Name length */ + __u8 file_type; + char name[EXT2_NAME_LEN]; /* File name */ +}; + +/* + * This is a bogus directory entry at the end of each leaf block that + * records checksums. + */ +struct ext2_dir_entry_tail { + __u32 det_reserved_zero1; /* Pretend to be unused */ + __u16 det_rec_len; /* 12 */ + __u16 det_reserved_name_len; /* 0xDE00, fake namelen/filetype */ + __u32 det_checksum; /* crc32c(uuid+inode+dirent) */ +}; + +/* + * Ext2 directory file types. Only the low 3 bits are used. The + * other bits are reserved for now. + */ +#define EXT2_FT_UNKNOWN 0 +#define EXT2_FT_REG_FILE 1 +#define EXT2_FT_DIR 2 +#define EXT2_FT_CHRDEV 3 +#define EXT2_FT_BLKDEV 4 +#define EXT2_FT_FIFO 5 +#define EXT2_FT_SOCK 6 +#define EXT2_FT_SYMLINK 7 + +#define EXT2_FT_MAX 8 + +/* + * Annoyingly, e2fsprogs always swab16s ext2_dir_entry.name_len, so we + * have to build ext2_dir_entry_tail with that assumption too. This + * constant helps to build the dir_entry_tail to look like it has an + * "invalid" file type. + */ +#define EXT2_DIR_NAME_LEN_CSUM 0xDE00 + +/* + * EXT2_DIR_PAD defines the directory entries boundaries + * + * NOTE: It must be a multiple of 4 + */ +#define EXT2_DIR_ENTRY_HEADER_LEN 8 +#define EXT2_DIR_PAD 4 +#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) +#define EXT2_DIR_REC_LEN(name_len) (((name_len) + \ + EXT2_DIR_ENTRY_HEADER_LEN + \ + EXT2_DIR_ROUND) & \ + ~EXT2_DIR_ROUND) + +/* + * Constants for ext4's extended time encoding + */ +#define EXT4_EPOCH_BITS 2 +#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1) +#define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS) + +/* + * This structure is used for multiple mount protection. It is written + * into the block number saved in the s_mmp_block field in the superblock. + * Programs that check MMP should assume that if SEQ_FSCK (or any unknown + * code above SEQ_MAX) is present then it is NOT safe to use the filesystem, + * regardless of how old the timestamp is. + * + * The timestamp in the MMP structure will be updated by e2fsck at some + * arbitrary intervals (start of passes, after every few groups of inodes + * in pass1 and pass1b). There is no guarantee that e2fsck is updating + * the MMP block in a timely manner, and the updates it does are purely + * for the convenience of the sysadmin and not for automatic validation. + * + * Note: Only the mmp_seq value is used to determine whether the MMP block + * is being updated. The mmp_time, mmp_nodename, and mmp_bdevname + * fields are only for informational purposes for the administrator, + * due to clock skew between nodes and hostname HA service takeover. + */ +#define EXT4_MMP_MAGIC 0x004D4D50U /* ASCII for MMP */ +#define EXT4_MMP_SEQ_CLEAN 0xFF4D4D50U /* mmp_seq value for clean unmount */ +#define EXT4_MMP_SEQ_FSCK 0xE24D4D50U /* mmp_seq value when being fscked */ +#define EXT4_MMP_SEQ_MAX 0xE24D4D4FU /* maximum valid mmp_seq value */ + +/* Not endian-annotated; it's swapped at read/write time */ +struct mmp_struct { + __u32 mmp_magic; /* Magic number for MMP */ + __u32 mmp_seq; /* Sequence no. updated periodically */ + __u64 mmp_time; /* Time last updated */ + char mmp_nodename[64]; /* Node which last updated MMP block */ + char mmp_bdevname[32]; /* Bdev which last updated MMP block */ + __u16 mmp_check_interval; /* Changed mmp_check_interval */ + __u16 mmp_pad1; + __u32 mmp_pad2[226]; + __u32 mmp_checksum; /* crc32c(uuid+mmp_block) */ +}; + +/* + * Default interval for MMP update in seconds. + */ +#define EXT4_MMP_UPDATE_INTERVAL 5 + +/* + * Maximum interval for MMP update in seconds. + */ +#define EXT4_MMP_MAX_UPDATE_INTERVAL 300 + +/* + * Minimum interval for MMP checking in seconds. + */ +#define EXT4_MMP_MIN_CHECK_INTERVAL 5 + +/* + * Minimum size of inline data. + */ +#define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__u32) * EXT2_N_BLOCKS)) + +/* + * Size of a parent inode in inline data directory. + */ +#define EXT4_INLINE_DATA_DOTDOT_SIZE (4) + +#endif /* _LINUX_EXT2_FS_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libext2fs/ext2fs/ext2_io.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libext2fs/ext2fs/ext2_io.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,147 @@ +/* + * io.h --- the I/O manager abstraction + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _EXT2FS_EXT2_IO_H +#define _EXT2FS_EXT2_IO_H + +#include + +/* + * ext2_loff_t is defined here since unix_io.c needs it. + */ +#if defined(__GNUC__) || defined(HAS_LONG_LONG) +typedef long long ext2_loff_t; +#else +typedef long ext2_loff_t; +#endif + +/* llseek.c */ +ext2_loff_t ext2fs_llseek (int, ext2_loff_t, int); + +typedef struct struct_io_manager *io_manager; +typedef struct struct_io_channel *io_channel; +typedef struct struct_io_stats *io_stats; + +#define CHANNEL_FLAGS_WRITETHROUGH 0x01 +#define CHANNEL_FLAGS_DISCARD_ZEROES 0x02 +#define CHANNEL_FLAGS_BLOCK_DEVICE 0x04 + +#define io_channel_discard_zeroes_data(i) (i->flags & CHANNEL_FLAGS_DISCARD_ZEROES) + +struct struct_io_channel { + errcode_t magic; + io_manager manager; + char *name; + int block_size; + errcode_t (*read_error)(io_channel channel, + unsigned long block, + int count, + void *data, + size_t size, + int actual_bytes_read, + errcode_t error); + errcode_t (*write_error)(io_channel channel, + unsigned long block, + int count, + const void *data, + size_t size, + int actual_bytes_written, + errcode_t error); + int refcount; + int flags; + long reserved[14]; + void *private_data; + void *app_data; + int align; +}; + +struct struct_io_stats { + int num_fields; + int reserved; + unsigned long long bytes_read; + unsigned long long bytes_written; +}; + +struct struct_io_manager { + errcode_t magic; + const char *name; + errcode_t (*open)(const char *name, int flags, io_channel *channel); + errcode_t (*close)(io_channel channel); + errcode_t (*set_blksize)(io_channel channel, int blksize); + errcode_t (*read_blk)(io_channel channel, unsigned long block, + int count, void *data); + errcode_t (*write_blk)(io_channel channel, unsigned long block, + int count, const void *data); + errcode_t (*flush)(io_channel channel); + errcode_t (*write_byte)(io_channel channel, unsigned long offset, + int count, const void *data); + errcode_t (*set_option)(io_channel channel, const char *option, + const char *arg); + errcode_t (*get_stats)(io_channel channel, io_stats *io_stats); + errcode_t (*read_blk64)(io_channel channel, unsigned long long block, + int count, void *data); + errcode_t (*write_blk64)(io_channel channel, unsigned long long block, + int count, const void *data); + errcode_t (*discard)(io_channel channel, unsigned long long block, + unsigned long long count); + errcode_t (*cache_readahead)(io_channel channel, + unsigned long long block, + unsigned long long count); + errcode_t (*zeroout)(io_channel channel, unsigned long long block, + unsigned long long count); + long reserved[14]; +}; + +#define IO_FLAG_RW 0x0001 +#define IO_FLAG_EXCLUSIVE 0x0002 +#define IO_FLAG_DIRECT_IO 0x0004 +#define IO_FLAG_FORCE_BOUNCE 0x0008 + +/* + * Convenience functions.... + */ +#define io_channel_close(c) ((c)->manager->close((c))) +#define io_channel_set_blksize(c,s) ((c)->manager->set_blksize((c),s)) +#define io_channel_read_blk(c,b,n,d) ((c)->manager->read_blk((c),b,n,d)) +#define io_channel_write_blk(c,b,n,d) ((c)->manager->write_blk((c),b,n,d)) +#define io_channel_flush(c) ((c)->manager->flush((c))) +#define io_channel_bumpcount(c) ((c)->refcount++) + +/* io_manager.c */ +extern errcode_t io_channel_set_options(io_channel channel, + const char *options); +extern errcode_t io_channel_write_byte(io_channel channel, + unsigned long offset, + int count, const void *data); +extern errcode_t io_channel_read_blk64(io_channel channel, + unsigned long long block, + int count, void *data); +extern errcode_t io_channel_write_blk64(io_channel channel, + unsigned long long block, + int count, const void *data); +extern errcode_t io_channel_discard(io_channel channel, + unsigned long long block, + unsigned long long count); +extern errcode_t io_channel_zeroout(io_channel channel, + unsigned long long block, + unsigned long long count); +extern errcode_t io_channel_alloc_buf(io_channel channel, + int count, void *ptr); +extern errcode_t io_channel_cache_readahead(io_channel io, + unsigned long long block, + unsigned long long count); + +/* unix_io.c */ +extern io_manager unix_io_manager; +extern io_manager unixfd_io_manager; + +#endif /* _EXT2FS_EXT2_IO_H */ + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libext2fs/ext2fs/ext2_types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libext2fs/ext2fs/ext2_types.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,205 @@ +/* + * If linux/types.h is already been included, assume it has defined + * everything we need. (cross fingers) Other header files may have + * also defined the types that we need. + */ +#if (!defined(_LINUX_TYPES_H) && !defined(_BLKID_TYPES_H) && \ + !defined(_EXT2_TYPES_H)) +#define _EXT2_TYPES_H + +#define __S8_TYPEDEF __signed__ char +#define __U8_TYPEDEF unsigned char +#define __S16_TYPEDEF __signed__ short +#define __U16_TYPEDEF unsigned short +#define __S32_TYPEDEF __signed__ int +#define __U32_TYPEDEF unsigned int +#define __S64_TYPEDEF __signed__ long long +#define __U64_TYPEDEF unsigned long long + +#ifndef HAVE___U8 +#define HAVE___U8 +#ifdef __U8_TYPEDEF +typedef __U8_TYPEDEF __u8; +#else +typedef unsigned char __u8; +#endif +#endif /* HAVE___U8 */ + +#ifndef HAVE___S8 +#define HAVE___S8 +#ifdef __S8_TYPEDEF +typedef __S8_TYPEDEF __s8; +#else +typedef signed char __s8; +#endif +#endif /* HAVE___S8 */ + +#ifndef HAVE___U16 +#define HAVE___U16 +#ifdef __U16_TYPEDEF +typedef __U16_TYPEDEF __u16; +#else +#if (4 == 2) +typedef unsigned int __u16; +#else +#if (2 == 2) +typedef unsigned short __u16; +#else +#undef HAVE___U16 + ?==error: undefined 16 bit type +#endif /* SIZEOF_SHORT == 2 */ +#endif /* SIZEOF_INT == 2 */ +#endif /* __U16_TYPEDEF */ +#endif /* HAVE___U16 */ + +#ifndef HAVE___S16 +#define HAVE___S16 +#ifdef __S16_TYPEDEF +typedef __S16_TYPEDEF __s16; +#else +#if (4 == 2) +typedef int __s16; +#else +#if (2 == 2) +typedef short __s16; +#else +#undef HAVE___S16 + ?==error: undefined 16 bit type +#endif /* SIZEOF_SHORT == 2 */ +#endif /* SIZEOF_INT == 2 */ +#endif /* __S16_TYPEDEF */ +#endif /* HAVE___S16 */ + +#ifndef HAVE___U32 +#define HAVE___U32 +#ifdef __U32_TYPEDEF +typedef __U32_TYPEDEF __u32; +#else +#if (4 == 4) +typedef unsigned int __u32; +#else +#if (4 == 4) +typedef unsigned long __u32; +#else +#if (2 == 4) +typedef unsigned short __u32; +#else +#undef HAVE___U32 + ?== error: undefined 32 bit type +#endif /* SIZEOF_SHORT == 4 */ +#endif /* SIZEOF_LONG == 4 */ +#endif /* SIZEOF_INT == 4 */ +#endif /* __U32_TYPEDEF */ +#endif /* HAVE___U32 */ + +#ifndef HAVE___S32 +#define HAVE___S32 +#ifdef __S32_TYPEDEF +typedef __S32_TYPEDEF __s32; +#else +#if (4 == 4) +typedef int __s32; +#else +#if (4 == 4) +typedef long __s32; +#else +#if (2 == 4) +typedef short __s32; +#else +#undef HAVE___S32 + ?== error: undefined 32 bit type +#endif /* SIZEOF_SHORT == 4 */ +#endif /* SIZEOF_LONG == 4 */ +#endif /* SIZEOF_INT == 4 */ +#endif /* __S32_TYPEDEF */ +#endif /* HAVE___S32 */ + +#ifndef HAVE___U64 +#define HAVE___U64 +#ifdef __U64_TYPEDEF +typedef __U64_TYPEDEF __u64; +#else +#if (4 == 8) +typedef unsigned int __u64; +#else +#if (8 == 8) +typedef unsigned long long __u64; +#else +#if (4 == 8) +typedef unsigned long __u64; +#else +#undef HAVE___U64 + ?== error: undefined 64 bit type +#endif /* SIZEOF_LONG_LONG == 8 */ +#endif /* SIZEOF_LONG == 8 */ +#endif /* SIZEOF_INT == 8 */ +#endif /* __U64_TYPEDEF */ +#endif /* HAVE___U64 */ + +#ifndef HAVE___S64 +#define HAVE___S64 +#ifdef __S64_TYPEDEF +typedef __S64_TYPEDEF __s64; +#else +#if (4 == 8) +typedef int __s64; +#else +#if (8 == 8) +#if defined(__GNUC__) +typedef __signed__ long long __s64; +#else +typedef signed long long __s64; +#endif /* __GNUC__ */ +#else +#if (4 == 8) +typedef long __s64; +#else +#undef HAVE___S64 + ?== error: undefined 64 bit type +#endif /* SIZEOF_LONG_LONG == 8 */ +#endif /* SIZEOF_LONG == 8 */ +#endif /* SIZEOF_INT == 8 */ +#endif /* __S64_TYPEDEF */ +#endif /* HAVE___S64 */ + +#undef __S8_TYPEDEF +#undef __U8_TYPEDEF +#undef __S16_TYPEDEF +#undef __U16_TYPEDEF +#undef __S32_TYPEDEF +#undef __U32_TYPEDEF +#undef __S64_TYPEDEF +#undef __U64_TYPEDEF + +#endif /* _*_TYPES_H */ + +#include + +/* endian checking stuff */ +#ifndef EXT2_ENDIAN_H_ +#define EXT2_ENDIAN_H_ + +#ifdef __CHECKER__ +# ifndef __bitwise +# define __bitwise __attribute__((bitwise)) +# endif +#define __force __attribute__((force)) +#else +# ifndef __bitwise +# define __bitwise +# endif +#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; + +#endif /* EXT2_ENDIAN_H_ */ + +/* These defines are needed for the public ext2fs.h header file */ +#define HAVE_SYS_TYPES_H 1 +#undef WORDS_BIGENDIAN diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libext2fs/ext2fs/ext2fs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libext2fs/ext2fs/ext2fs.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,2048 @@ +/* + * ext2fs.h --- ext2fs + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _EXT2FS_EXT2FS_H +#define _EXT2FS_EXT2FS_H + +#ifdef __GNUC__ +#define EXT2FS_ATTR(x) __attribute__(x) +#else +#define EXT2FS_ATTR(x) +#endif + +#ifdef CONFIG_TDB +#define EXT2FS_NO_TDB_UNUSED +#else +#define EXT2FS_NO_TDB_UNUSED EXT2FS_ATTR((unused)) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Non-GNU C compilers won't necessarily understand inline + */ +#if (!defined(__GNUC__) && !defined(__WATCOMC__)) +#define NO_INLINE_FUNCS +#endif + +/* + * Where the master copy of the superblock is located, and how big + * superblocks are supposed to be. We define SUPERBLOCK_SIZE because + * the size of the superblock structure is not necessarily trustworthy + * (some versions have the padding set up so that the superblock is + * 1032 bytes long). + */ +#define SUPERBLOCK_OFFSET 1024 +#define SUPERBLOCK_SIZE 1024 + +#define UUID_STR_SIZE 37 + +/* + * The last ext2fs revision level that this version of the library is + * able to support. + */ +#define EXT2_LIB_CURRENT_REV EXT2_DYNAMIC_REV + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include +#include +#include +#include +#include + +#if EXT2_FLAT_INCLUDES +#include "e2_types.h" +#include "ext2_fs.h" +#include "ext3_extents.h" +#else +#include +#include +#include +#endif /* EXT2_FLAT_INCLUDES */ + +typedef __u32 __bitwise ext2_ino_t; +typedef __u32 __bitwise blk_t; +typedef __u64 __bitwise blk64_t; +typedef __u32 __bitwise dgrp_t; +typedef __u32 __bitwise ext2_off_t; +typedef __u64 __bitwise ext2_off64_t; +typedef __s64 __bitwise e2_blkcnt_t; +typedef __u32 __bitwise ext2_dirhash_t; + +#if EXT2_FLAT_INCLUDES +#include "com_err.h" +#include "ext2_io.h" +#include "ext2_err.h" +#include "ext2_ext_attr.h" +#else +#include +#include +#include +#include +#endif + +#include "hashmap.h" + +/* + * Portability help for Microsoft Visual C++ + */ +#ifdef _MSC_VER +#define EXT2_QSORT_TYPE int __cdecl +#else +#define EXT2_QSORT_TYPE int +#endif + +typedef struct struct_ext2_filsys *ext2_filsys; + +#define EXT2FS_MARK_ERROR 0 +#define EXT2FS_UNMARK_ERROR 1 +#define EXT2FS_TEST_ERROR 2 + +typedef struct ext2fs_struct_generic_bitmap *ext2fs_generic_bitmap; +typedef struct ext2fs_struct_generic_bitmap *ext2fs_inode_bitmap; +typedef struct ext2fs_struct_generic_bitmap *ext2fs_block_bitmap; + +#define EXT2_FIRST_INODE(s) EXT2_FIRST_INO(s) + + +/* + * Badblocks list definitions + */ + +typedef struct ext2_struct_u32_list *ext2_badblocks_list; +typedef struct ext2_struct_u32_iterate *ext2_badblocks_iterate; + +typedef struct ext2_struct_u32_list *ext2_u32_list; +typedef struct ext2_struct_u32_iterate *ext2_u32_iterate; + +/* old */ +typedef struct ext2_struct_u32_list *badblocks_list; +typedef struct ext2_struct_u32_iterate *badblocks_iterate; + +#define BADBLOCKS_FLAG_DIRTY 1 + +/* + * ext2_dblist structure and abstractions (see dblist.c) + */ +struct ext2_db_entry2 { + ext2_ino_t ino; + blk64_t blk; + e2_blkcnt_t blockcnt; +}; + +/* Ye Olde 32-bit version */ +struct ext2_db_entry { + ext2_ino_t ino; + blk_t blk; + int blockcnt; +}; + +typedef struct ext2_struct_dblist *ext2_dblist; + +#define DBLIST_ABORT 1 + +/* + * ext2_fileio definitions + */ + +#define EXT2_FILE_WRITE 0x0001 +#define EXT2_FILE_CREATE 0x0002 + +#define EXT2_FILE_MASK 0x00FF + +#define EXT2_FILE_BUF_DIRTY 0x4000 +#define EXT2_FILE_BUF_VALID 0x2000 + +typedef struct ext2_file *ext2_file_t; + +#define EXT2_SEEK_SET 0 +#define EXT2_SEEK_CUR 1 +#define EXT2_SEEK_END 2 + +/* + * Flags for the ext2_filsys structure and for ext2fs_open() + */ +#define EXT2_FLAG_RW 0x01 +#define EXT2_FLAG_CHANGED 0x02 +#define EXT2_FLAG_DIRTY 0x04 +#define EXT2_FLAG_VALID 0x08 +#define EXT2_FLAG_IB_DIRTY 0x10 +#define EXT2_FLAG_BB_DIRTY 0x20 +#define EXT2_FLAG_SWAP_BYTES 0x40 +#define EXT2_FLAG_SWAP_BYTES_READ 0x80 +#define EXT2_FLAG_SWAP_BYTES_WRITE 0x100 +#define EXT2_FLAG_MASTER_SB_ONLY 0x200 +#define EXT2_FLAG_FORCE 0x400 +#define EXT2_FLAG_SUPER_ONLY 0x800 +#define EXT2_FLAG_JOURNAL_DEV_OK 0x1000 +#define EXT2_FLAG_IMAGE_FILE 0x2000 +#define EXT2_FLAG_EXCLUSIVE 0x4000 +#define EXT2_FLAG_SOFTSUPP_FEATURES 0x8000 +#define EXT2_FLAG_NOFREE_ON_ERROR 0x10000 +#define EXT2_FLAG_64BITS 0x20000 +#define EXT2_FLAG_PRINT_PROGRESS 0x40000 +#define EXT2_FLAG_DIRECT_IO 0x80000 +#define EXT2_FLAG_SKIP_MMP 0x100000 +#define EXT2_FLAG_IGNORE_CSUM_ERRORS 0x200000 +#define EXT2_FLAG_SHARE_DUP 0x400000 +#define EXT2_FLAG_IGNORE_SB_ERRORS 0x800000 + +/* + * Special flag in the ext2 inode i_flag field that means that this is + * a new inode. (So that ext2_write_inode() can clear extra fields.) + */ +#define EXT2_NEW_INODE_FL 0x80000000 + +/* + * Flags for mkjournal + */ +#define EXT2_MKJOURNAL_V1_SUPER 0x0000001 /* create V1 superblock (deprecated) */ +#define EXT2_MKJOURNAL_LAZYINIT 0x0000002 /* don't zero journal inode before use*/ +#define EXT2_MKJOURNAL_NO_MNT_CHECK 0x0000004 /* don't check mount status */ + +struct blk_alloc_ctx; +struct opaque_ext2_group_desc; + +struct struct_ext2_filsys { + errcode_t magic; + io_channel io; + int flags; + char * device_name; + struct ext2_super_block * super; + unsigned int blocksize; + int fragsize; + dgrp_t group_desc_count; + unsigned long desc_blocks; + struct opaque_ext2_group_desc * group_desc; + unsigned int inode_blocks_per_group; + ext2fs_inode_bitmap inode_map; + ext2fs_block_bitmap block_map; + /* XXX FIXME-64: not 64-bit safe, but not used? */ + errcode_t (*get_blocks)(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks); + errcode_t (*check_directory)(ext2_filsys fs, ext2_ino_t ino); + errcode_t (*write_bitmaps)(ext2_filsys fs); + errcode_t (*read_inode)(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode); + errcode_t (*write_inode)(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode); + ext2_badblocks_list badblocks; + ext2_dblist dblist; + __u32 stride; /* for mke2fs */ + struct ext2_super_block * orig_super; + struct ext2_image_hdr * image_header; + __u32 umask; + time_t now; + int cluster_ratio_bits; + __u16 default_bitmap_type; + __u16 pad; + /* + * Reserved for future expansion + */ + __u32 reserved[5]; + + /* + * Reserved for the use of the calling application. + */ + void * priv_data; + + /* + * Inode cache + */ + struct ext2_inode_cache *icache; + io_channel image_io; + + /* + * More callback functions + */ + errcode_t (*get_alloc_block)(ext2_filsys fs, blk64_t goal, + blk64_t *ret); + errcode_t (*get_alloc_block2)(ext2_filsys fs, blk64_t goal, + blk64_t *ret, struct blk_alloc_ctx *ctx); + void (*block_alloc_stats)(ext2_filsys fs, blk64_t blk, int inuse); + + /* + * Buffers for Multiple mount protection(MMP) block. + */ + void *mmp_buf; + void *mmp_cmp; + int mmp_fd; + + /* + * Time at which e2fsck last updated the MMP block. + */ + long mmp_last_written; + + /* progress operation functions */ + struct ext2fs_progress_ops *progress_ops; + + /* Precomputed FS UUID checksum for seeding other checksums */ + __u32 csum_seed; + + io_channel journal_io; + char *journal_name; + + /* New block range allocation hooks */ + errcode_t (*new_range)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen); + void (*block_alloc_stats_range)(ext2_filsys fs, blk64_t blk, blk_t num, + int inuse); + + /* hashmap for SHA of data blocks */ + struct ext2fs_hashmap* block_sha_map; +}; + +#if EXT2_FLAT_INCLUDES +#include "e2_bitops.h" +#else +#include +#endif + +/* + * 64-bit bitmap backend types + */ +#define EXT2FS_BMAP64_BITARRAY 1 +#define EXT2FS_BMAP64_RBTREE 2 +#define EXT2FS_BMAP64_AUTODIR 3 + +/* + * Return flags for the block iterator functions + */ +#define BLOCK_CHANGED 1 +#define BLOCK_ABORT 2 +#define BLOCK_ERROR 4 +#define BLOCK_INLINE_DATA_CHANGED 8 + +/* + * Block interate flags + * + * BLOCK_FLAG_APPEND, or BLOCK_FLAG_HOLE, indicates that the interator + * function should be called on blocks where the block number is zero. + * This is used by ext2fs_expand_dir() to be able to add a new block + * to an inode. It can also be used for programs that want to be able + * to deal with files that contain "holes". + * + * BLOCK_FLAG_DEPTH_TRAVERSE indicates that the iterator function for + * the indirect, doubly indirect, etc. blocks should be called after + * all of the blocks contained in the indirect blocks are processed. + * This is useful if you are going to be deallocating blocks from an + * inode. + * + * BLOCK_FLAG_DATA_ONLY indicates that the iterator function should be + * called for data blocks only. + * + * BLOCK_FLAG_READ_ONLY is a promise by the caller that it will not + * modify returned block number. + * + * BLOCK_FLAG_NO_LARGE is for internal use only. It informs + * ext2fs_block_iterate2 that large files won't be accepted. + */ +#define BLOCK_FLAG_APPEND 1 +#define BLOCK_FLAG_HOLE 1 +#define BLOCK_FLAG_DEPTH_TRAVERSE 2 +#define BLOCK_FLAG_DATA_ONLY 4 +#define BLOCK_FLAG_READ_ONLY 8 + +#define BLOCK_FLAG_NO_LARGE 0x1000 + +/* + * Magic "block count" return values for the block iterator function. + */ +#define BLOCK_COUNT_IND (-1) +#define BLOCK_COUNT_DIND (-2) +#define BLOCK_COUNT_TIND (-3) +#define BLOCK_COUNT_TRANSLATOR (-4) + +#define BLOCK_ALLOC_UNKNOWN 0 +#define BLOCK_ALLOC_DATA 1 +#define BLOCK_ALLOC_METADATA 2 + +struct blk_alloc_ctx { + ext2_ino_t ino; + struct ext2_inode *inode; + blk64_t lblk; + int flags; +}; + +/* + * Flags for ext2fs_move_blocks + */ +#if 0 +#define EXT2_BMOVE_GET_DBLIST 0x0001 +#define EXT2_BMOVE_DEBUG 0x0002 +#endif + +/* + * Generic (non-filesystem layout specific) extents structure + */ + +#define EXT2_EXTENT_FLAGS_LEAF 0x0001 +#define EXT2_EXTENT_FLAGS_UNINIT 0x0002 +#define EXT2_EXTENT_FLAGS_SECOND_VISIT 0x0004 + +struct ext2fs_extent { + blk64_t e_pblk; /* first physical block */ + blk64_t e_lblk; /* first logical block extent covers */ + __u32 e_len; /* number of blocks covered by extent */ + __u32 e_flags; /* extent flags */ +}; + +typedef struct ext2_extent_handle *ext2_extent_handle_t; +typedef struct ext2_extent_path *ext2_extent_path_t; + +/* + * Flags used by ext2fs_extent_get() + */ +#define EXT2_EXTENT_CURRENT 0x0000 +#define EXT2_EXTENT_MOVE_MASK 0x000F +#define EXT2_EXTENT_ROOT 0x0001 +#define EXT2_EXTENT_LAST_LEAF 0x0002 +#define EXT2_EXTENT_FIRST_SIB 0x0003 +#define EXT2_EXTENT_LAST_SIB 0x0004 +#define EXT2_EXTENT_NEXT_SIB 0x0005 +#define EXT2_EXTENT_PREV_SIB 0x0006 +#define EXT2_EXTENT_NEXT_LEAF 0x0007 +#define EXT2_EXTENT_PREV_LEAF 0x0008 +#define EXT2_EXTENT_NEXT 0x0009 +#define EXT2_EXTENT_PREV 0x000A +#define EXT2_EXTENT_UP 0x000B +#define EXT2_EXTENT_DOWN 0x000C +#define EXT2_EXTENT_DOWN_AND_LAST 0x000D + +/* + * Flags used by ext2fs_extent_insert() + */ +#define EXT2_EXTENT_INSERT_AFTER 0x0001 /* insert after handle loc'n */ +#define EXT2_EXTENT_INSERT_NOSPLIT 0x0002 /* insert may not cause split */ + +/* + * Flags used by ext2fs_extent_delete() + */ +#define EXT2_EXTENT_DELETE_KEEP_EMPTY 0x001 /* keep node if last extent gone */ + +/* + * Flags used by ext2fs_extent_set_bmap() + */ +#define EXT2_EXTENT_SET_BMAP_UNINIT 0x0001 + +/* + * Data structure returned by ext2fs_extent_get_info() + */ +struct ext2_extent_info { + int curr_entry; + int curr_level; + int num_entries; + int max_entries; + int max_depth; + int bytes_avail; + blk64_t max_lblk; + blk64_t max_pblk; + __u32 max_len; + __u32 max_uninit_len; +}; + +/* + * Flags for directory block reading and writing functions + */ +#define EXT2_DIRBLOCK_V2_STRUCT 0x0001 + +/* + * Return flags for the directory iterator functions + */ +#define DIRENT_CHANGED 1 +#define DIRENT_ABORT 2 +#define DIRENT_ERROR 3 + +/* + * Directory iterator flags + */ + +#define DIRENT_FLAG_INCLUDE_EMPTY 1 +#define DIRENT_FLAG_INCLUDE_REMOVED 2 +#define DIRENT_FLAG_INCLUDE_CSUM 4 +#define DIRENT_FLAG_INCLUDE_INLINE_DATA 8 + +#define DIRENT_DOT_FILE 1 +#define DIRENT_DOT_DOT_FILE 2 +#define DIRENT_OTHER_FILE 3 +#define DIRENT_DELETED_FILE 4 +#define DIRENT_CHECKSUM 5 + +/* + * Inode scan definitions + */ +typedef struct ext2_struct_inode_scan *ext2_inode_scan; + +/* + * ext2fs_scan flags + */ +#define EXT2_SF_CHK_BADBLOCKS 0x0001 +#define EXT2_SF_BAD_INODE_BLK 0x0002 +#define EXT2_SF_BAD_EXTRA_BYTES 0x0004 +#define EXT2_SF_SKIP_MISSING_ITABLE 0x0008 +#define EXT2_SF_DO_LAZY 0x0010 +#define EXT2_SF_WARN_GARBAGE_INODES 0x0020 + +/* + * ext2fs_check_if_mounted flags + */ +#define EXT2_MF_MOUNTED 1 +#define EXT2_MF_ISROOT 2 +#define EXT2_MF_READONLY 4 +#define EXT2_MF_SWAP 8 +#define EXT2_MF_BUSY 16 + +/* + * Ext2/linux mode flags. We define them here so that we don't need + * to depend on the OS's sys/stat.h, since we may be compiling on a + * non-Linux system. + */ +#define LINUX_S_IFMT 00170000 +#define LINUX_S_IFSOCK 0140000 +#define LINUX_S_IFLNK 0120000 +#define LINUX_S_IFREG 0100000 +#define LINUX_S_IFBLK 0060000 +#define LINUX_S_IFDIR 0040000 +#define LINUX_S_IFCHR 0020000 +#define LINUX_S_IFIFO 0010000 +#define LINUX_S_ISUID 0004000 +#define LINUX_S_ISGID 0002000 +#define LINUX_S_ISVTX 0001000 + +#define LINUX_S_IRWXU 00700 +#define LINUX_S_IRUSR 00400 +#define LINUX_S_IWUSR 00200 +#define LINUX_S_IXUSR 00100 + +#define LINUX_S_IRWXG 00070 +#define LINUX_S_IRGRP 00040 +#define LINUX_S_IWGRP 00020 +#define LINUX_S_IXGRP 00010 + +#define LINUX_S_IRWXO 00007 +#define LINUX_S_IROTH 00004 +#define LINUX_S_IWOTH 00002 +#define LINUX_S_IXOTH 00001 + +#define LINUX_S_ISLNK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFLNK) +#define LINUX_S_ISREG(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFREG) +#define LINUX_S_ISDIR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFDIR) +#define LINUX_S_ISCHR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFCHR) +#define LINUX_S_ISBLK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFBLK) +#define LINUX_S_ISFIFO(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFIFO) +#define LINUX_S_ISSOCK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFSOCK) + +/* + * ext2 size of an inode + */ +#define EXT2_I_SIZE(i) ((i)->i_size | ((__u64) (i)->i_size_high << 32)) + +/* + * ext2_icount_t abstraction + */ +#define EXT2_ICOUNT_OPT_INCREMENT 0x01 +#define EXT2_ICOUNT_OPT_FULLMAP 0x02 + +typedef struct ext2_icount *ext2_icount_t; + +/* + * Flags for ext2fs_bmap + */ +#define BMAP_ALLOC 0x0001 +#define BMAP_SET 0x0002 +#define BMAP_UNINIT 0x0004 +#define BMAP_ZERO 0x0008 + +/* + * Returned flags from ext2fs_bmap + */ +#define BMAP_RET_UNINIT 0x0001 + +/* + * Flags for imager.c functions + */ +#define IMAGER_FLAG_INODEMAP 1 +#define IMAGER_FLAG_SPARSEWRITE 2 + +/* + * For checking structure magic numbers... + */ + +#define EXT2_CHECK_MAGIC(struct, code) \ + if ((struct)->magic != (code)) return (code) + +/* + * Features supported by this version of the library + */ +#define EXT2_LIB_FEATURE_COMPAT_SUPP (EXT2_FEATURE_COMPAT_DIR_PREALLOC|\ + EXT2_FEATURE_COMPAT_IMAGIC_INODES|\ + EXT3_FEATURE_COMPAT_HAS_JOURNAL|\ + EXT2_FEATURE_COMPAT_RESIZE_INODE|\ + EXT2_FEATURE_COMPAT_DIR_INDEX|\ + EXT2_FEATURE_COMPAT_EXT_ATTR|\ + EXT4_FEATURE_COMPAT_SPARSE_SUPER2) + +#ifdef CONFIG_MMP +#define EXT4_LIB_INCOMPAT_MMP EXT4_FEATURE_INCOMPAT_MMP +#else +#define EXT4_LIB_INCOMPAT_MMP (0) +#endif + +#define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\ + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\ + EXT2_FEATURE_INCOMPAT_META_BG|\ + EXT3_FEATURE_INCOMPAT_RECOVER|\ + EXT3_FEATURE_INCOMPAT_EXTENTS|\ + EXT4_FEATURE_INCOMPAT_FLEX_BG|\ + EXT4_FEATURE_INCOMPAT_EA_INODE|\ + EXT4_LIB_INCOMPAT_MMP|\ + EXT4_FEATURE_INCOMPAT_64BIT|\ + EXT4_FEATURE_INCOMPAT_INLINE_DATA|\ + EXT4_FEATURE_INCOMPAT_ENCRYPT|\ + EXT4_FEATURE_INCOMPAT_CSUM_SEED|\ + EXT4_FEATURE_INCOMPAT_LARGEDIR) + +#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\ + EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE|\ + EXT4_FEATURE_RO_COMPAT_DIR_NLINK|\ + EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|\ + EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\ + EXT4_FEATURE_RO_COMPAT_BIGALLOC|\ + EXT4_FEATURE_RO_COMPAT_QUOTA|\ + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\ + EXT4_FEATURE_RO_COMPAT_READONLY |\ + EXT4_FEATURE_RO_COMPAT_PROJECT |\ + EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS |\ + EXT4_FEATURE_RO_COMPAT_VERITY) + +/* + * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed + * to ext2fs_openfs() + */ +#define EXT2_LIB_SOFTSUPP_INCOMPAT (0) +#define EXT2_LIB_SOFTSUPP_RO_COMPAT (EXT4_FEATURE_RO_COMPAT_REPLICA) + + +/* Translate a block number to a cluster number */ +#define EXT2FS_CLUSTER_RATIO(fs) (1 << (fs)->cluster_ratio_bits) +#define EXT2FS_CLUSTER_MASK(fs) (EXT2FS_CLUSTER_RATIO(fs) - 1) +#define EXT2FS_B2C(fs, blk) ((blk) >> (fs)->cluster_ratio_bits) +/* Translate a cluster number to a block number */ +#define EXT2FS_C2B(fs, cluster) ((cluster) << (fs)->cluster_ratio_bits) +/* Translate # of blks to # of clusters */ +#define EXT2FS_NUM_B2C(fs, blks) (((blks) + EXT2FS_CLUSTER_MASK(fs)) >> \ + (fs)->cluster_ratio_bits) + +#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) +typedef struct stat64 ext2fs_struct_stat; +#else +typedef struct stat ext2fs_struct_stat; +#endif + +/* + * For ext2fs_close2() and ext2fs_flush2(), this flag allows you to + * avoid the fsync call. + */ +#define EXT2_FLAG_FLUSH_NO_SYNC 1 + +/* + * Modify and iterate extended attributes + */ +struct ext2_xattr_handle; +#define XATTR_ABORT 1 +#define XATTR_CHANGED 2 + +/* + * function prototypes + */ +static inline int ext2fs_has_group_desc_csum(ext2_filsys fs) +{ + return ext2fs_has_feature_metadata_csum(fs->super) || + ext2fs_has_feature_gdt_csum(fs->super); +} + +/* The LARGE_FILE feature should be set if we have stored files 2GB+ in size */ +static inline int ext2fs_needs_large_file_feature(unsigned long long file_size) +{ + return file_size >= 0x80000000ULL; +} + +/* alloc.c */ +extern void ext2fs_clear_block_uninit(ext2_filsys fs, dgrp_t group); +extern errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, int mode, + ext2fs_inode_bitmap map, ext2_ino_t *ret); +extern errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal, + ext2fs_block_bitmap map, blk_t *ret); +extern errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal, + ext2fs_block_bitmap map, blk64_t *ret); +extern errcode_t ext2fs_new_block3(ext2_filsys fs, blk64_t goal, + ext2fs_block_bitmap map, blk64_t *ret, + struct blk_alloc_ctx *ctx); +extern errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, + blk_t finish, int num, + ext2fs_block_bitmap map, + blk_t *ret); +extern errcode_t ext2fs_get_free_blocks2(ext2_filsys fs, blk64_t start, + blk64_t finish, int num, + ext2fs_block_bitmap map, + blk64_t *ret); +extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal, + char *block_buf, blk_t *ret); +extern errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal, + char *block_buf, blk64_t *ret); +extern errcode_t ext2fs_alloc_block3(ext2_filsys fs, blk64_t goal, + char *block_buf, blk64_t *ret, + struct blk_alloc_ctx *ctx); + +extern void ext2fs_set_alloc_block_callback(ext2_filsys fs, + errcode_t (*func)(ext2_filsys fs, + blk64_t goal, + blk64_t *ret), + errcode_t (**old)(ext2_filsys fs, + blk64_t goal, + blk64_t *ret)); +blk64_t ext2fs_find_inode_goal(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t lblk); +extern void ext2fs_set_new_range_callback(ext2_filsys fs, + errcode_t (*func)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen), + errcode_t (**old)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen)); +extern void ext2fs_set_block_alloc_stats_range_callback(ext2_filsys fs, + void (*func)(ext2_filsys fs, blk64_t blk, + blk_t num, int inuse), + void (**old)(ext2_filsys fs, blk64_t blk, + blk_t num, int inuse)); +#define EXT2_NEWRANGE_FIXED_GOAL (0x1) +#define EXT2_NEWRANGE_MIN_LENGTH (0x2) +#define EXT2_NEWRANGE_ALL_FLAGS (0x3) +errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk, + blk64_t *plen); +#define EXT2_ALLOCRANGE_FIXED_GOAL (0x1) +#define EXT2_ALLOCRANGE_ZERO_BLOCKS (0x2) +#define EXT2_ALLOCRANGE_ALL_FLAGS (0x3) +errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal, + blk_t len, blk64_t *ret); + +/* alloc_sb.c */ +extern int ext2fs_reserve_super_and_bgd(ext2_filsys fs, + dgrp_t group, + ext2fs_block_bitmap bmap); +extern void ext2fs_set_block_alloc_stats_callback(ext2_filsys fs, + void (*func)(ext2_filsys fs, + blk64_t blk, + int inuse), + void (**old)(ext2_filsys fs, + blk64_t blk, + int inuse)); + +/* alloc_stats.c */ +void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse); +void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino, + int inuse, int isdir); +void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse); +void ext2fs_block_alloc_stats2(ext2_filsys fs, blk64_t blk, int inuse); +void ext2fs_block_alloc_stats_range(ext2_filsys fs, blk64_t blk, + blk_t num, int inuse); + +/* alloc_tables.c */ +extern errcode_t ext2fs_allocate_tables(ext2_filsys fs); +extern errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, + ext2fs_block_bitmap bmap); + +/* badblocks.c */ +extern errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size); +extern errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk); +extern int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk); +extern int ext2fs_u32_list_test(ext2_u32_list bb, blk_t blk); +extern errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb, + ext2_u32_iterate *ret); +extern int ext2fs_u32_list_iterate(ext2_u32_iterate iter, blk_t *blk); +extern void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter); +extern errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest); +extern int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2); + +extern errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, + int size); +extern errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, + blk_t blk); +extern int ext2fs_badblocks_list_test(ext2_badblocks_list bb, + blk_t blk); +extern int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk); +extern void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk); +extern errcode_t + ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb, + ext2_badblocks_iterate *ret); +extern int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, + blk_t *blk); +extern void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter); +extern errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src, + ext2_badblocks_list *dest); +extern int ext2fs_badblocks_equal(ext2_badblocks_list bb1, + ext2_badblocks_list bb2); +extern int ext2fs_u32_list_count(ext2_u32_list bb); + +/* bb_compat */ +extern errcode_t badblocks_list_create(badblocks_list *ret, int size); +extern errcode_t badblocks_list_add(badblocks_list bb, blk_t blk); +extern int badblocks_list_test(badblocks_list bb, blk_t blk); +extern errcode_t badblocks_list_iterate_begin(badblocks_list bb, + badblocks_iterate *ret); +extern int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk); +extern void badblocks_list_iterate_end(badblocks_iterate iter); +extern void badblocks_list_free(badblocks_list bb); + +/* bb_inode.c */ +extern errcode_t ext2fs_update_bb_inode(ext2_filsys fs, + ext2_badblocks_list bb_list); + +/* bitmaps.c */ +extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap); +extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap); +extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap *dest); +extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs); +extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs); +extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs); +extern errcode_t ext2fs_read_block_bitmap(ext2_filsys fs); +extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_block_bitmap *ret); +extern errcode_t ext2fs_allocate_subcluster_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_block_bitmap *ret); +extern int ext2fs_get_bitmap_granularity(ext2fs_block_bitmap bitmap); +extern errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_inode_bitmap *ret); +extern errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap, + ext2_ino_t end, ext2_ino_t *oend); +extern errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap, + blk_t end, blk_t *oend); +extern errcode_t ext2fs_fudge_block_bitmap_end2(ext2fs_block_bitmap bitmap, + blk64_t end, blk64_t *oend); +extern void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap); +extern void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap); +extern errcode_t ext2fs_read_bitmaps(ext2_filsys fs); +extern errcode_t ext2fs_write_bitmaps(ext2_filsys fs); +extern errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end, + ext2fs_inode_bitmap bmap); +extern errcode_t ext2fs_resize_inode_bitmap2(__u64 new_end, + __u64 new_real_end, + ext2fs_inode_bitmap bmap); +extern errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end, + ext2fs_block_bitmap bmap); +extern errcode_t ext2fs_resize_block_bitmap2(__u64 new_end, + __u64 new_real_end, + ext2fs_block_bitmap bmap); +extern errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1, + ext2fs_block_bitmap bm2); +extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1, + ext2fs_inode_bitmap bm2); +extern errcode_t ext2fs_set_inode_bitmap_range(ext2fs_inode_bitmap bmap, + ext2_ino_t start, unsigned int num, + void *in); +extern errcode_t ext2fs_set_inode_bitmap_range2(ext2fs_inode_bitmap bmap, + __u64 start, size_t num, + void *in); +extern errcode_t ext2fs_get_inode_bitmap_range(ext2fs_inode_bitmap bmap, + ext2_ino_t start, unsigned int num, + void *out); +extern errcode_t ext2fs_get_inode_bitmap_range2(ext2fs_inode_bitmap bmap, + __u64 start, size_t num, + void *out); +extern errcode_t ext2fs_set_block_bitmap_range(ext2fs_block_bitmap bmap, + blk_t start, unsigned int num, + void *in); +extern errcode_t ext2fs_set_block_bitmap_range2(ext2fs_block_bitmap bmap, + blk64_t start, size_t num, + void *in); +extern errcode_t ext2fs_get_block_bitmap_range(ext2fs_block_bitmap bmap, + blk_t start, unsigned int num, + void *out); +extern errcode_t ext2fs_get_block_bitmap_range2(ext2fs_block_bitmap bmap, + blk64_t start, size_t num, + void *out); + +/* blknum.c */ +extern __u32 ext2fs_inode_bitmap_checksum(ext2_filsys fs, dgrp_t group); +extern __u32 ext2fs_block_bitmap_checksum(ext2_filsys fs, dgrp_t group); +extern dgrp_t ext2fs_group_of_blk2(ext2_filsys fs, blk64_t); +extern blk64_t ext2fs_group_first_block2(ext2_filsys fs, dgrp_t group); +extern blk64_t ext2fs_group_last_block2(ext2_filsys fs, dgrp_t group); +extern int ext2fs_group_blocks_count(ext2_filsys fs, dgrp_t group); +extern blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs, + struct ext2_inode *inode); +extern blk64_t ext2fs_inode_i_blocks(ext2_filsys fs, + struct ext2_inode *inode); +extern blk64_t ext2fs_blocks_count(struct ext2_super_block *super); +extern void ext2fs_blocks_count_set(struct ext2_super_block *super, + blk64_t blk); +extern void ext2fs_blocks_count_add(struct ext2_super_block *super, + blk64_t blk); +extern blk64_t ext2fs_r_blocks_count(struct ext2_super_block *super); +extern void ext2fs_r_blocks_count_set(struct ext2_super_block *super, + blk64_t blk); +extern void ext2fs_r_blocks_count_add(struct ext2_super_block *super, + blk64_t blk); +extern blk64_t ext2fs_free_blocks_count(struct ext2_super_block *super); +extern void ext2fs_free_blocks_count_set(struct ext2_super_block *super, + blk64_t blk); +extern void ext2fs_free_blocks_count_add(struct ext2_super_block *super, + blk64_t blk); +/* Block group descriptor accessor functions */ +extern struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs, + struct opaque_ext2_group_desc *gdp, + dgrp_t group); +extern blk64_t ext2fs_block_bitmap_csum(ext2_filsys fs, dgrp_t group); +extern blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group); +extern void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group, + blk64_t blk); +extern __u32 ext2fs_inode_bitmap_csum(ext2_filsys fs, dgrp_t group); +extern blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group); +extern void ext2fs_inode_bitmap_loc_set(ext2_filsys fs, dgrp_t group, + blk64_t blk); +extern blk64_t ext2fs_inode_table_loc(ext2_filsys fs, dgrp_t group); +extern void ext2fs_inode_table_loc_set(ext2_filsys fs, dgrp_t group, + blk64_t blk); +extern __u32 ext2fs_bg_free_blocks_count(ext2_filsys fs, dgrp_t group); +extern void ext2fs_bg_free_blocks_count_set(ext2_filsys fs, dgrp_t group, + __u32 n); +extern __u32 ext2fs_bg_free_inodes_count(ext2_filsys fs, dgrp_t group); +extern void ext2fs_bg_free_inodes_count_set(ext2_filsys fs, dgrp_t group, + __u32 n); +extern __u32 ext2fs_bg_used_dirs_count(ext2_filsys fs, dgrp_t group); +extern void ext2fs_bg_used_dirs_count_set(ext2_filsys fs, dgrp_t group, + __u32 n); +extern __u32 ext2fs_bg_itable_unused(ext2_filsys fs, dgrp_t group); +extern void ext2fs_bg_itable_unused_set(ext2_filsys fs, dgrp_t group, + __u32 n); +extern __u16 ext2fs_bg_flags(ext2_filsys fs, dgrp_t group); +extern void ext2fs_bg_flags_zap(ext2_filsys fs, dgrp_t group); +extern int ext2fs_bg_flags_test(ext2_filsys fs, dgrp_t group, __u16 bg_flag); +extern void ext2fs_bg_flags_set(ext2_filsys fs, dgrp_t group, __u16 bg_flags); +extern void ext2fs_bg_flags_clear(ext2_filsys fs, dgrp_t group, __u16 bg_flags); +extern __u16 ext2fs_bg_checksum(ext2_filsys fs, dgrp_t group); +extern void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group, __u16 checksum); +extern blk64_t ext2fs_file_acl_block(ext2_filsys fs, + const struct ext2_inode *inode); +extern void ext2fs_file_acl_block_set(ext2_filsys fs, + struct ext2_inode *inode, blk64_t blk); +extern errcode_t ext2fs_inode_size_set(ext2_filsys fs, struct ext2_inode *inode, + ext2_off64_t size); + +/* block.c */ +extern errcode_t ext2fs_block_iterate(ext2_filsys fs, + ext2_ino_t ino, + int flags, + char *block_buf, + int (*func)(ext2_filsys fs, + blk_t *blocknr, + int blockcnt, + void *priv_data), + void *priv_data); +errcode_t ext2fs_block_iterate2(ext2_filsys fs, + ext2_ino_t ino, + int flags, + char *block_buf, + int (*func)(ext2_filsys fs, + blk_t *blocknr, + e2_blkcnt_t blockcnt, + blk_t ref_blk, + int ref_offset, + void *priv_data), + void *priv_data); +errcode_t ext2fs_block_iterate3(ext2_filsys fs, + ext2_ino_t ino, + int flags, + char *block_buf, + int (*func)(ext2_filsys fs, + blk64_t *blocknr, + e2_blkcnt_t blockcnt, + blk64_t ref_blk, + int ref_offset, + void *priv_data), + void *priv_data); + +/* bmap.c */ +extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + char *block_buf, int bmap_flags, + blk_t block, blk_t *phys_blk); +extern errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + char *block_buf, int bmap_flags, blk64_t block, + int *ret_flags, blk64_t *phys_blk); +errcode_t ext2fs_map_cluster_block(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t lblk, + blk64_t *pblk); + +#if 0 +/* bmove.c */ +extern errcode_t ext2fs_move_blocks(ext2_filsys fs, + ext2fs_block_bitmap reserve, + ext2fs_block_bitmap alloc_map, + int flags); +#endif + +/* check_desc.c */ +extern errcode_t ext2fs_check_desc(ext2_filsys fs); + +/* closefs.c */ +extern errcode_t ext2fs_close(ext2_filsys fs); +extern errcode_t ext2fs_close2(ext2_filsys fs, int flags); +extern errcode_t ext2fs_close_free(ext2_filsys *fs); +extern errcode_t ext2fs_flush(ext2_filsys fs); +extern errcode_t ext2fs_flush2(ext2_filsys fs, int flags); +extern int ext2fs_bg_has_super(ext2_filsys fs, dgrp_t group_block); +extern errcode_t ext2fs_super_and_bgd_loc2(ext2_filsys fs, + dgrp_t group, + blk64_t *ret_super_blk, + blk64_t *ret_old_desc_blk, + blk64_t *ret_new_desc_blk, + blk_t *ret_used_blks); +extern int ext2fs_super_and_bgd_loc(ext2_filsys fs, + dgrp_t group, + blk_t *ret_super_blk, + blk_t *ret_old_desc_blk, + blk_t *ret_new_desc_blk, + int *ret_meta_bg); +extern void ext2fs_update_dynamic_rev(ext2_filsys fs); + +/* crc32c.c */ +extern __u32 ext2fs_crc32_be(__u32 crc, unsigned char const *p, size_t len); +extern __u32 ext2fs_crc32c_le(__u32 crc, unsigned char const *p, size_t len); + +/* csum.c */ +extern void ext2fs_init_csum_seed(ext2_filsys fs); +extern errcode_t ext2fs_mmp_csum_set(ext2_filsys fs, struct mmp_struct *mmp); +extern int ext2fs_mmp_csum_verify(ext2_filsys, struct mmp_struct *mmp); +extern int ext2fs_verify_csum_type(ext2_filsys fs, struct ext2_super_block *sb); +extern errcode_t ext2fs_superblock_csum_set(ext2_filsys fs, + struct ext2_super_block *sb); +extern int ext2fs_superblock_csum_verify(ext2_filsys fs, + struct ext2_super_block *sb); +extern errcode_t ext2fs_ext_attr_block_csum_set(ext2_filsys fs, + ext2_ino_t inum, blk64_t block, + struct ext2_ext_attr_header *hdr); +extern int ext2fs_ext_attr_block_csum_verify(ext2_filsys fs, ext2_ino_t inum, + blk64_t block, + struct ext2_ext_attr_header *hdr); +#define EXT2_DIRENT_TAIL(block, blocksize) \ + ((struct ext2_dir_entry_tail *)(((char *)(block)) + \ + (blocksize) - sizeof(struct ext2_dir_entry_tail))) + +extern void ext2fs_initialize_dirent_tail(ext2_filsys fs, + struct ext2_dir_entry_tail *t); +extern int ext2fs_dirent_has_tail(ext2_filsys fs, + struct ext2_dir_entry *dirent); +extern int ext2fs_dirent_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent); +extern int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent); +extern errcode_t ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent); +extern errcode_t ext2fs_get_dx_countlimit(ext2_filsys fs, + struct ext2_dir_entry *dirent, + struct ext2_dx_countlimit **cc, + int *offset); +extern errcode_t ext2fs_extent_block_csum_set(ext2_filsys fs, + ext2_ino_t inum, + struct ext3_extent_header *eh); +extern int ext2fs_extent_block_csum_verify(ext2_filsys fs, + ext2_ino_t inum, + struct ext3_extent_header *eh); +extern errcode_t ext2fs_block_bitmap_csum_set(ext2_filsys fs, dgrp_t group, + char *bitmap, int size); +extern int ext2fs_block_bitmap_csum_verify(ext2_filsys fs, dgrp_t group, + char *bitmap, int size); +extern errcode_t ext2fs_inode_bitmap_csum_set(ext2_filsys fs, dgrp_t group, + char *bitmap, int size); +extern int ext2fs_inode_bitmap_csum_verify(ext2_filsys fs, dgrp_t group, + char *bitmap, int size); +extern errcode_t ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_inode_large *inode); +extern int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_inode_large *inode); +extern void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group); +extern int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group); +extern errcode_t ext2fs_set_gdt_csum(ext2_filsys fs); +extern __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group); + +/* dblist.c */ +extern errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist); +extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, + blk_t blk, int blockcnt); +extern errcode_t ext2fs_add_dir_block2(ext2_dblist dblist, ext2_ino_t ino, + blk64_t blk, e2_blkcnt_t blockcnt); +extern void ext2fs_dblist_sort(ext2_dblist dblist, + EXT2_QSORT_TYPE (*sortfunc)(const void *, + const void *)); +extern void ext2fs_dblist_sort2(ext2_dblist dblist, + EXT2_QSORT_TYPE (*sortfunc)(const void *, + const void *)); +extern errcode_t ext2fs_dblist_iterate(ext2_dblist dblist, + int (*func)(ext2_filsys fs, struct ext2_db_entry *db_info, + void *priv_data), + void *priv_data); +extern errcode_t ext2fs_dblist_iterate2(ext2_dblist dblist, + int (*func)(ext2_filsys fs, struct ext2_db_entry2 *db_info, + void *priv_data), + void *priv_data); +extern errcode_t ext2fs_dblist_iterate3(ext2_dblist dblist, + int (*func)(ext2_filsys fs, struct ext2_db_entry2 *db_info, + void *priv_data), + unsigned long long start, + unsigned long long count, + void *priv_data); +extern errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, + blk_t blk, int blockcnt); +extern errcode_t ext2fs_set_dir_block2(ext2_dblist dblist, ext2_ino_t ino, + blk64_t blk, e2_blkcnt_t blockcnt); +extern errcode_t ext2fs_copy_dblist(ext2_dblist src, + ext2_dblist *dest); +extern int ext2fs_dblist_count(ext2_dblist dblist); +extern blk64_t ext2fs_dblist_count2(ext2_dblist dblist); +extern errcode_t ext2fs_dblist_get_last(ext2_dblist dblist, + struct ext2_db_entry **entry); +extern errcode_t ext2fs_dblist_get_last2(ext2_dblist dblist, + struct ext2_db_entry2 **entry); +extern errcode_t ext2fs_dblist_drop_last(ext2_dblist dblist); + +/* dblist_dir.c */ +extern errcode_t + ext2fs_dblist_dir_iterate(ext2_dblist dblist, + int flags, + char *block_buf, + int (*func)(ext2_ino_t dir, + int entry, + struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data), + void *priv_data); + +#if 0 +/* digest_encode.c */ +#define EXT2FS_DIGEST_SIZE EXT2FS_SHA256_LENGTH +extern int ext2fs_digest_encode(const char *src, int len, char *dst); +extern int ext2fs_digest_decode(const char *src, int len, char *dst); +#endif + +/* dirblock.c */ +extern errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block, + void *buf); +extern errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block, + void *buf, int flags); +extern errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block, + void *buf, int flags); +extern errcode_t ext2fs_read_dir_block4(ext2_filsys fs, blk64_t block, + void *buf, int flags, ext2_ino_t ino); +extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block, + void *buf); +extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block, + void *buf, int flags); +extern errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block, + void *buf, int flags); +extern errcode_t ext2fs_write_dir_block4(ext2_filsys fs, blk64_t block, + void *buf, int flags, ext2_ino_t ino); + +/* dirhash.c */ +extern errcode_t ext2fs_dirhash(int version, const char *name, int len, + const __u32 *seed, + ext2_dirhash_t *ret_hash, + ext2_dirhash_t *ret_minor_hash); + + +/* dir_iterate.c */ +extern errcode_t ext2fs_get_rec_len(ext2_filsys fs, + struct ext2_dir_entry *dirent, + unsigned int *rec_len); +extern errcode_t ext2fs_set_rec_len(ext2_filsys fs, + unsigned int len, + struct ext2_dir_entry *dirent); +extern errcode_t ext2fs_dir_iterate(ext2_filsys fs, + ext2_ino_t dir, + int flags, + char *block_buf, + int (*func)(struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data), + void *priv_data); +extern errcode_t ext2fs_dir_iterate2(ext2_filsys fs, + ext2_ino_t dir, + int flags, + char *block_buf, + int (*func)(ext2_ino_t dir, + int entry, + struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data), + void *priv_data); + +/* dupfs.c */ +extern errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest); + +/* expanddir.c */ +extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir); + +/* ext_attr.c */ +extern __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, + void *data); +extern errcode_t ext2fs_ext_attr_hash_entry2(ext2_filsys fs, + struct ext2_ext_attr_entry *entry, + void *data, __u32 *hash); +extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf); +extern errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block, + void *buf); +extern errcode_t ext2fs_read_ext_attr3(ext2_filsys fs, blk64_t block, + void *buf, ext2_ino_t inum); +extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, + void *buf); +extern errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block, + void *buf); +extern errcode_t ext2fs_write_ext_attr3(ext2_filsys fs, blk64_t block, + void *buf, ext2_ino_t inum); +extern errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk, + char *block_buf, + int adjust, __u32 *newcount); +extern errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk, + char *block_buf, + int adjust, __u32 *newcount); +extern errcode_t ext2fs_adjust_ea_refcount3(ext2_filsys fs, blk64_t blk, + char *block_buf, + int adjust, __u32 *newcount, + ext2_ino_t inum); +errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle); +errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle); +errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h, + int (*func)(char *name, char *value, + size_t value_len, void *data), + void *data); +errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key, + void **value, size_t *value_len); +errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle, + const char *key, + const void *value, + size_t value_len); +errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle, + const char *key); +errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino, + struct ext2_xattr_handle **handle); +errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle); +errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode_large *inode); +errcode_t ext2fs_xattrs_count(struct ext2_xattr_handle *handle, size_t *count); +errcode_t ext2fs_xattr_inode_max_size(ext2_filsys fs, ext2_ino_t ino, + size_t *size); +#define XATTR_HANDLE_FLAG_RAW 0x0001 +errcode_t ext2fs_xattrs_flags(struct ext2_xattr_handle *handle, + unsigned int *new_flags, unsigned int *old_flags); +extern void ext2fs_ext_attr_block_rehash(struct ext2_ext_attr_header *header, + struct ext2_ext_attr_entry *end); +extern __u32 ext2fs_get_ea_inode_hash(struct ext2_inode *inode); +extern void ext2fs_set_ea_inode_hash(struct ext2_inode *inode, __u32 hash); +extern __u64 ext2fs_get_ea_inode_ref(struct ext2_inode *inode); +extern void ext2fs_set_ea_inode_ref(struct ext2_inode *inode, __u64 ref_count); + +/* extent.c */ +extern errcode_t ext2fs_extent_header_verify(void *ptr, int size); +extern errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino, + ext2_extent_handle_t *handle); +extern errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + ext2_extent_handle_t *ret_handle); +extern void ext2fs_extent_free(ext2_extent_handle_t handle); +extern errcode_t ext2fs_extent_get(ext2_extent_handle_t handle, + int flags, struct ext2fs_extent *extent); +extern errcode_t ext2fs_extent_node_split(ext2_extent_handle_t handle); +extern errcode_t ext2fs_extent_replace(ext2_extent_handle_t handle, int flags, + struct ext2fs_extent *extent); +extern errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags, + struct ext2fs_extent *extent); +extern errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle, + blk64_t logical, blk64_t physical, + int flags); +extern errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, int flags); +extern errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle, + struct ext2_extent_info *info); +extern errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle, + blk64_t blk); +extern errcode_t ext2fs_extent_goto2(ext2_extent_handle_t handle, + int leaf_level, blk64_t blk); +extern errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle); +size_t ext2fs_max_extent_depth(ext2_extent_handle_t handle); + +/* fallocate.c */ +#define EXT2_FALLOCATE_ZERO_BLOCKS (0x1) +#define EXT2_FALLOCATE_FORCE_INIT (0x2) +#define EXT2_FALLOCATE_FORCE_UNINIT (0x4) +#define EXT2_FALLOCATE_INIT_BEYOND_EOF (0x8) +#define EXT2_FALLOCATE_ALL_FLAGS (0xF) +errcode_t ext2fs_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t goal, + blk64_t start, blk64_t len); + +/* fileio.c */ +extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + int flags, ext2_file_t *ret); +extern errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino, + int flags, ext2_file_t *ret); +extern ext2_filsys ext2fs_file_get_fs(ext2_file_t file); +struct ext2_inode *ext2fs_file_get_inode(ext2_file_t file); +extern ext2_ino_t ext2fs_file_get_inode_num(ext2_file_t file); +extern errcode_t ext2fs_file_close(ext2_file_t file); +extern errcode_t ext2fs_file_flush(ext2_file_t file); +extern errcode_t ext2fs_file_read(ext2_file_t file, void *buf, + unsigned int wanted, unsigned int *got); +extern errcode_t ext2fs_file_write(ext2_file_t file, const void *buf, + unsigned int nbytes, unsigned int *written); +extern errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset, + int whence, __u64 *ret_pos); +extern errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset, + int whence, ext2_off_t *ret_pos); +errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size); +extern ext2_off_t ext2fs_file_get_size(ext2_file_t file); +extern errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size); +extern errcode_t ext2fs_file_set_size2(ext2_file_t file, ext2_off64_t size); + +/* finddev.c */ +extern char *ext2fs_find_block_device(dev_t device); + +/* flushb.c */ +extern errcode_t ext2fs_sync_device(int fd, int flushb); + +/* freefs.c */ +extern void ext2fs_free(ext2_filsys fs); +extern void ext2fs_free_dblist(ext2_dblist dblist); +extern void ext2fs_badblocks_list_free(ext2_badblocks_list bb); +extern void ext2fs_u32_list_free(ext2_u32_list bb); + +/* gen_bitmap.c */ +extern void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap); +extern errcode_t ext2fs_make_generic_bitmap(errcode_t magic, ext2_filsys fs, + __u32 start, __u32 end, + __u32 real_end, + const char *descr, char *init_map, + ext2fs_generic_bitmap *ret); +extern errcode_t ext2fs_allocate_generic_bitmap(__u32 start, + __u32 end, + __u32 real_end, + const char *descr, + ext2fs_generic_bitmap *ret); +extern errcode_t ext2fs_copy_generic_bitmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap *dest); +extern void ext2fs_clear_generic_bitmap(ext2fs_generic_bitmap bitmap); +extern errcode_t ext2fs_fudge_generic_bitmap_end(ext2fs_inode_bitmap bitmap, + errcode_t magic, + errcode_t neq, + ext2_ino_t end, + ext2_ino_t *oend); +extern void ext2fs_set_generic_bitmap_padding(ext2fs_generic_bitmap map); +extern errcode_t ext2fs_resize_generic_bitmap(errcode_t magic, + __u32 new_end, + __u32 new_real_end, + ext2fs_generic_bitmap bmap); +extern errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq, + ext2fs_generic_bitmap bm1, + ext2fs_generic_bitmap bm2); +extern errcode_t ext2fs_get_generic_bitmap_range(ext2fs_generic_bitmap bmap, + errcode_t magic, + __u32 start, __u32 num, + void *out); +extern errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap bmap, + errcode_t magic, + __u32 start, __u32 num, + void *in); +extern errcode_t ext2fs_find_first_zero_generic_bitmap(ext2fs_generic_bitmap bitmap, + __u32 start, __u32 end, + __u32 *out); +extern errcode_t ext2fs_find_first_set_generic_bitmap(ext2fs_generic_bitmap bitmap, + __u32 start, __u32 end, + __u32 *out); + +/* gen_bitmap64.c */ +void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap); +errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic, + int type, __u64 start, __u64 end, + __u64 real_end, + const char *descr, + ext2fs_generic_bitmap *ret); +errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap *dest); +void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap); +errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap, + errcode_t neq, + __u64 end, __u64 *oend); +void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap); +errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap, + __u64 new_end, + __u64 new_real_end); +errcode_t ext2fs_compare_generic_bmap(errcode_t neq, + ext2fs_generic_bitmap bm1, + ext2fs_generic_bitmap bm2); +errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap, + __u64 start, unsigned int num, + void *out); +errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap, + __u64 start, unsigned int num, + void *in); +errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, + ext2fs_block_bitmap *bitmap); + +/* get_num_dirs.c */ +extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs); + +/* getsize.c */ +extern errcode_t ext2fs_get_device_size(const char *file, int blocksize, + blk_t *retblocks); +extern errcode_t ext2fs_get_device_size2(const char *file, int blocksize, + blk64_t *retblocks); + +/* getsectsize.c */ +extern int ext2fs_get_dio_alignment(int fd); +errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize); +errcode_t ext2fs_get_device_phys_sectsize(const char *file, int *sectsize); + +/* i_block.c */ +errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode, + blk64_t num_blocks); +errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode, + blk64_t num_blocks); +errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t b); + +/* imager.c */ +extern errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags); + +/* ind_block.c */ +errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf); +errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf); + +/* initialize.c */ +extern errcode_t ext2fs_initialize(const char *name, int flags, + struct ext2_super_block *param, + io_manager manager, ext2_filsys *ret_fs); + +/* icount.c */ +extern void ext2fs_free_icount(ext2_icount_t icount); +extern errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir, + int flags, ext2_icount_t *ret); +extern errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, + unsigned int size, + ext2_icount_t hint, ext2_icount_t *ret); +extern errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, + unsigned int size, + ext2_icount_t *ret); +extern errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, + __u16 *ret); +extern errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino, + __u16 *ret); +extern errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino, + __u16 *ret); +extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino, + __u16 count); +extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount); +errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *); + +/* inline.c */ + +extern errcode_t ext2fs_get_memalign(unsigned long size, + unsigned long align, void *ptr); + +/* inline_data.c */ +extern errcode_t ext2fs_inline_data_init(ext2_filsys fs, ext2_ino_t ino); +extern errcode_t ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino, + size_t *size); +extern errcode_t ext2fs_inline_data_get(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + void *buf, size_t *size); +extern errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + void *buf, size_t size); + +/* inode.c */ +extern errcode_t ext2fs_create_inode_cache(ext2_filsys fs, + unsigned int cache_size); +extern void ext2fs_free_inode_cache(struct ext2_inode_cache *icache); +extern errcode_t ext2fs_flush_icache(ext2_filsys fs); +extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, + ext2_ino_t *ino, + struct ext2_inode *inode, + int bufsize); +#define EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS 8 +extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, + ext2_inode_scan *ret_scan); +extern void ext2fs_close_inode_scan(ext2_inode_scan scan); +extern errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino, + struct ext2_inode *inode); +extern errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan, + int group); +extern void ext2fs_set_inode_callback + (ext2_inode_scan scan, + errcode_t (*done_group)(ext2_filsys fs, + ext2_inode_scan scan, + dgrp_t group, + void * priv_data), + void *done_group_data); +extern int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags, + int clear_flags); +extern errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode, + int bufsize); +extern errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode); +extern errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode, + int bufsize); +extern errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode); +extern errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode); +extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks); +extern errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino); + +/* inode_io.c */ +extern io_manager inode_io_manager; +extern errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino, + char **name); +extern errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + char **name); + +/* ismounted.c */ +extern errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags); +extern errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags, + char *mtpt, int mtlen); + +/* punch.c */ +/* + * NOTE: This function removes from an inode the blocks "start", "end", and + * every block in between. + */ +extern errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + char *block_buf, blk64_t start, + blk64_t end); + +/* namei.c */ +extern errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name, + int namelen, char *buf, ext2_ino_t *inode); +extern errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, + const char *name, ext2_ino_t *inode); +errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, + const char *name, ext2_ino_t *inode); +extern errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, + ext2_ino_t inode, ext2_ino_t *res_inode); + +/* native.c */ +int ext2fs_native_flag(void); + +/* newdir.c */ +extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino, + ext2_ino_t parent_ino, char **block); +extern errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs, ext2_ino_t dir_ino, + ext2_ino_t parent_ino, __u32 *iblock); + +/* mkdir.c */ +extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, + const char *name); + +/* mkjournal.c */ +extern errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num, + blk_t *ret_blk, int *ret_count); +extern errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num, + blk64_t *ret_blk, int *ret_count); +extern errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, + __u32 num_blocks, int flags, + char **ret_jsb); +extern errcode_t ext2fs_add_journal_device(ext2_filsys fs, + ext2_filsys journal_dev); +extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, + int flags); +extern errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks, + blk64_t goal, int flags); +extern int ext2fs_default_journal_size(__u64 num_blocks); +extern int ext2fs_journal_sb_start(int blocksize); + +/* openfs.c */ +extern errcode_t ext2fs_open(const char *name, int flags, int superblock, + unsigned int block_size, io_manager manager, + ext2_filsys *ret_fs); +extern errcode_t ext2fs_open2(const char *name, const char *io_options, + int flags, int superblock, + unsigned int block_size, io_manager manager, + ext2_filsys *ret_fs); +/* + * The dgrp_t argument to these two functions is not actually a group number + * but a block number offset within a group table! Convert with the formula + * (group_number / groups_per_block). + */ +extern blk64_t ext2fs_descriptor_block_loc2(ext2_filsys fs, + blk64_t group_block, dgrp_t i); +extern blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, + dgrp_t i); +errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io); +errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io); +errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io); + +/* get_pathname.c */ +extern errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino, + char **name); + +/* link.c */ +errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, + ext2_ino_t ino, int flags); +errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, const char *name, + ext2_ino_t ino, int flags); + +/* symlink.c */ +errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, + const char *name, const char *target); +int ext2fs_is_fast_symlink(struct ext2_inode *inode); + +/* mmp.c */ +errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf); +errcode_t ext2fs_mmp_write(ext2_filsys fs, blk64_t mmp_blk, void *buf); +errcode_t ext2fs_mmp_clear(ext2_filsys fs); +errcode_t ext2fs_mmp_init(ext2_filsys fs); +errcode_t ext2fs_mmp_start(ext2_filsys fs); +errcode_t ext2fs_mmp_update(ext2_filsys fs); +errcode_t ext2fs_mmp_update2(ext2_filsys fs, int immediately); +errcode_t ext2fs_mmp_stop(ext2_filsys fs); +unsigned ext2fs_mmp_new_seq(void); + +/* read_bb.c */ +extern errcode_t ext2fs_read_bb_inode(ext2_filsys fs, + ext2_badblocks_list *bb_list); + +/* read_bb_file.c */ +extern errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f, + ext2_badblocks_list *bb_list, + void *priv_data, + void (*invalid)(ext2_filsys fs, + blk_t blk, + char *badstr, + void *priv_data)); +extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, + ext2_badblocks_list *bb_list, + void (*invalid)(ext2_filsys fs, + blk_t blk)); + +/* res_gdt.c */ +extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs); + +/*sha256.c */ +#define EXT2FS_SHA256_LENGTH 32 +#if 0 +extern void ext2fs_sha256(const unsigned char *in, unsigned long in_size, + unsigned char out[EXT2FS_SHA256_LENGTH]); +#endif + +/* sha512.c */ +#define EXT2FS_SHA512_LENGTH 64 +extern void ext2fs_sha512(const unsigned char *in, unsigned long in_size, + unsigned char out[EXT2FS_SHA512_LENGTH]); + +/* swapfs.c */ +extern errcode_t ext2fs_dirent_swab_in2(ext2_filsys fs, char *buf, size_t size, + int flags); +extern errcode_t ext2fs_dirent_swab_in(ext2_filsys fs, char *buf, int flags); +extern errcode_t ext2fs_dirent_swab_out2(ext2_filsys fs, char *buf, size_t size, + int flags); +extern errcode_t ext2fs_dirent_swab_out(ext2_filsys fs, char *buf, int flags); +extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, + int has_header); +extern void ext2fs_swap_ext_attr_header(struct ext2_ext_attr_header *to_header, + struct ext2_ext_attr_header *from_hdr); +extern void ext2fs_swap_ext_attr_entry(struct ext2_ext_attr_entry *to_entry, + struct ext2_ext_attr_entry *from_entry); +extern void ext2fs_swap_super(struct ext2_super_block * super); +extern void ext2fs_swap_group_desc(struct ext2_group_desc *gdp); +extern void ext2fs_swap_group_desc2(ext2_filsys, struct ext2_group_desc *gdp); +extern void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t, + struct ext2_inode_large *f, int hostorder, + int bufsize); +extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t, + struct ext2_inode *f, int hostorder); +extern void ext2fs_swap_mmp(struct mmp_struct *mmp); + +/* unix_io.c */ +extern int ext2fs_open_file(const char *pathname, int flags, mode_t mode); +extern int ext2fs_stat(const char *path, ext2fs_struct_stat *buf); +extern int ext2fs_fstat(int fd, ext2fs_struct_stat *buf); + +/* valid_blk.c */ +extern int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode); +extern int ext2fs_inode_has_valid_blocks2(ext2_filsys fs, + struct ext2_inode *inode); + +/* version.c */ +extern int ext2fs_parse_version_string(const char *ver_string); +extern int ext2fs_get_library_version(const char **ver_string, + const char **date_string); + +/* write_bb_file.c */ +extern errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list, + unsigned int flags, + FILE *f); + + +/* inline functions */ +#ifdef NO_INLINE_FUNCS +extern errcode_t ext2fs_get_mem(unsigned long size, void *ptr); +extern errcode_t ext2fs_get_memzero(unsigned long size, void *ptr); +extern errcode_t ext2fs_get_array(unsigned long count, + unsigned long size, void *ptr); +extern errcode_t ext2fs_get_arrayzero(unsigned long count, + unsigned long size, void *ptr); +extern errcode_t ext2fs_free_mem(void *ptr); +extern errcode_t ext2fs_resize_mem(unsigned long old_size, + unsigned long size, void *ptr); +extern void ext2fs_mark_super_dirty(ext2_filsys fs); +extern void ext2fs_mark_changed(ext2_filsys fs); +extern int ext2fs_test_changed(ext2_filsys fs); +extern void ext2fs_mark_valid(ext2_filsys fs); +extern void ext2fs_unmark_valid(ext2_filsys fs); +extern int ext2fs_test_valid(ext2_filsys fs); +extern void ext2fs_mark_ib_dirty(ext2_filsys fs); +extern void ext2fs_mark_bb_dirty(ext2_filsys fs); +extern int ext2fs_test_ib_dirty(ext2_filsys fs); +extern int ext2fs_test_bb_dirty(ext2_filsys fs); +extern dgrp_t ext2fs_group_of_blk(ext2_filsys fs, blk_t blk); +extern dgrp_t ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino); +extern blk_t ext2fs_group_first_block(ext2_filsys fs, dgrp_t group); +extern blk_t ext2fs_group_last_block(ext2_filsys fs, dgrp_t group); +extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs, + struct ext2_inode *inode); +extern int ext2fs_htree_intnode_maxrecs(ext2_filsys fs, int blocks); +extern unsigned int ext2fs_div_ceil(unsigned int a, unsigned int b); +extern __u64 ext2fs_div64_ceil(__u64 a, __u64 b); +extern int ext2fs_dirent_name_len(const struct ext2_dir_entry *entry); +extern void ext2fs_dirent_set_name_len(struct ext2_dir_entry *entry, int len); +extern int ext2fs_dirent_file_type(const struct ext2_dir_entry *entry); +extern void ext2fs_dirent_set_file_type(struct ext2_dir_entry *entry, int type); +extern struct ext2_inode *ext2fs_inode(struct ext2_inode_large * large_inode); +extern const struct ext2_inode *ext2fs_const_inode(const struct ext2_inode_large * large_inode); + +#endif + +/* + * The actual inlined functions definitions themselves... + * + * If NO_INLINE_FUNCS is defined, then we won't try to do inline + * functions at all! + */ +#if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS)) +#ifdef INCLUDE_INLINE_FUNCS +#define _INLINE_ extern +#else +#if (__STDC_VERSION__ >= 199901L) +#define _INLINE_ inline +#else +#ifdef __GNUC__ +#define _INLINE_ extern __inline__ +#else /* For Watcom C */ +#define _INLINE_ extern inline +#endif /* __GNUC__ */ +#endif /* __STDC_VERSION__ >= 199901L */ +#endif + +#ifndef EXT2_CUSTOM_MEMORY_ROUTINES +#include +/* + * Allocate memory. The 'ptr' arg must point to a pointer. + */ +_INLINE_ errcode_t ext2fs_get_mem(unsigned long size, void *ptr) +{ + void *pp; + + pp = malloc(size); + if (!pp) + return EXT2_ET_NO_MEMORY; + memcpy(ptr, &pp, sizeof (pp)); + return 0; +} + +_INLINE_ errcode_t ext2fs_get_memzero(unsigned long size, void *ptr) +{ + void *pp; + + pp = malloc(size); + if (!pp) + return EXT2_ET_NO_MEMORY; + memset(pp, 0, size); + memcpy(ptr, &pp, sizeof(pp)); + return 0; +} + +_INLINE_ errcode_t ext2fs_get_array(unsigned long count, unsigned long size, void *ptr) +{ + if (count && (~0UL)/count < size) + return EXT2_ET_NO_MEMORY; + return ext2fs_get_mem(count*size, ptr); +} + +_INLINE_ errcode_t ext2fs_get_arrayzero(unsigned long count, + unsigned long size, void *ptr) +{ + void *pp; + + if (count && (~0UL)/count < size) + return EXT2_ET_NO_MEMORY; + pp = calloc(count, size); + if (!pp) + return EXT2_ET_NO_MEMORY; + memcpy(ptr, &pp, sizeof(pp)); + return 0; +} + +/* + * Free memory. The 'ptr' arg must point to a pointer. + */ +_INLINE_ errcode_t ext2fs_free_mem(void *ptr) +{ + void *p; + + memcpy(&p, ptr, sizeof(p)); + free(p); + p = 0; + memcpy(ptr, &p, sizeof(p)); + return 0; +} + +/* + * Resize memory. The 'ptr' arg must point to a pointer. + */ +_INLINE_ errcode_t ext2fs_resize_mem(unsigned long EXT2FS_ATTR((unused)) old_size, + unsigned long size, void *ptr) +{ + void *p; + + /* Use "memcpy" for pointer assignments here to avoid problems + * with C99 strict type aliasing rules. */ + memcpy(&p, ptr, sizeof(p)); + p = realloc(p, size); + if (!p) + return EXT2_ET_NO_MEMORY; + memcpy(ptr, &p, sizeof(p)); + return 0; +} +#endif /* Custom memory routines */ + +/* + * Mark a filesystem superblock as dirty + */ +_INLINE_ void ext2fs_mark_super_dirty(ext2_filsys fs) +{ + fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_CHANGED; +} + +/* + * Mark a filesystem as changed + */ +_INLINE_ void ext2fs_mark_changed(ext2_filsys fs) +{ + fs->flags |= EXT2_FLAG_CHANGED; +} + +/* + * Check to see if a filesystem has changed + */ +_INLINE_ int ext2fs_test_changed(ext2_filsys fs) +{ + return (fs->flags & EXT2_FLAG_CHANGED); +} + +/* + * Mark a filesystem as valid + */ +_INLINE_ void ext2fs_mark_valid(ext2_filsys fs) +{ + fs->flags |= EXT2_FLAG_VALID; +} + +/* + * Mark a filesystem as NOT valid + */ +_INLINE_ void ext2fs_unmark_valid(ext2_filsys fs) +{ + fs->flags &= ~EXT2_FLAG_VALID; +} + +/* + * Check to see if a filesystem is valid + */ +_INLINE_ int ext2fs_test_valid(ext2_filsys fs) +{ + return (fs->flags & EXT2_FLAG_VALID); +} + +/* + * Mark the inode bitmap as dirty + */ +_INLINE_ void ext2fs_mark_ib_dirty(ext2_filsys fs) +{ + fs->flags |= EXT2_FLAG_IB_DIRTY | EXT2_FLAG_CHANGED; +} + +/* + * Mark the block bitmap as dirty + */ +_INLINE_ void ext2fs_mark_bb_dirty(ext2_filsys fs) +{ + fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_CHANGED; +} + +/* + * Check to see if a filesystem's inode bitmap is dirty + */ +_INLINE_ int ext2fs_test_ib_dirty(ext2_filsys fs) +{ + return (fs->flags & EXT2_FLAG_IB_DIRTY); +} + +/* + * Check to see if a filesystem's block bitmap is dirty + */ +_INLINE_ int ext2fs_test_bb_dirty(ext2_filsys fs) +{ + return (fs->flags & EXT2_FLAG_BB_DIRTY); +} + +/* + * Return the group # of a block + */ +_INLINE_ dgrp_t ext2fs_group_of_blk(ext2_filsys fs, blk_t blk) +{ + return ext2fs_group_of_blk2(fs, blk); +} +/* + * Return the group # of an inode number + */ +_INLINE_ dgrp_t ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino) +{ + return (ino - 1) / fs->super->s_inodes_per_group; +} + +/* + * Return the first block (inclusive) in a group + */ +_INLINE_ blk_t ext2fs_group_first_block(ext2_filsys fs, dgrp_t group) +{ + return (blk_t) ext2fs_group_first_block2(fs, group); +} + +/* + * Return the last block (inclusive) in a group + */ +_INLINE_ blk_t ext2fs_group_last_block(ext2_filsys fs, dgrp_t group) +{ + return (blk_t) ext2fs_group_last_block2(fs, group); +} + +_INLINE_ blk_t ext2fs_inode_data_blocks(ext2_filsys fs, + struct ext2_inode *inode) +{ + return (blk_t) ext2fs_inode_data_blocks2(fs, inode); +} + +_INLINE_ int ext2fs_htree_intnode_maxrecs(ext2_filsys fs, int blocks) +{ + return blocks * ((fs->blocksize - 8) / sizeof(struct ext2_dx_entry)); +} + +/* + * This is an efficient, overflow safe way of calculating ceil((1.0 * a) / b) + */ +_INLINE_ unsigned int ext2fs_div_ceil(unsigned int a, unsigned int b) +{ + if (!a) + return 0; + return ((a - 1) / b) + 1; +} + +_INLINE_ __u64 ext2fs_div64_ceil(__u64 a, __u64 b) +{ + if (!a) + return 0; + return ((a - 1) / b) + 1; +} + +_INLINE_ int ext2fs_dirent_name_len(const struct ext2_dir_entry *entry) +{ + return entry->name_len & 0xff; +} + +_INLINE_ void ext2fs_dirent_set_name_len(struct ext2_dir_entry *entry, int len) +{ + entry->name_len = (entry->name_len & 0xff00) | (len & 0xff); +} + +_INLINE_ int ext2fs_dirent_file_type(const struct ext2_dir_entry *entry) +{ + return entry->name_len >> 8; +} + +_INLINE_ void ext2fs_dirent_set_file_type(struct ext2_dir_entry *entry, int type) +{ + entry->name_len = (entry->name_len & 0xff) | (type << 8); +} + +_INLINE_ struct ext2_inode *ext2fs_inode(struct ext2_inode_large * large_inode) +{ + /* It is always safe to convert large inode to a small inode */ + return (struct ext2_inode *) large_inode; +} + +_INLINE_ const struct ext2_inode * +ext2fs_const_inode(const struct ext2_inode_large * large_inode) +{ + /* It is always safe to convert large inode to a small inode */ + return (const struct ext2_inode *) large_inode; +} + +#undef _INLINE_ +#endif + +/* htree levels for ext4 */ +#define EXT4_HTREE_LEVEL_COMPAT 2 +#define EXT4_HTREE_LEVEL 3 + +static inline unsigned int ext2_dir_htree_level(ext2_filsys fs) +{ + if (ext2fs_has_feature_largedir(fs->super)) + return EXT4_HTREE_LEVEL; + + return EXT4_HTREE_LEVEL_COMPAT; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _EXT2FS_EXT2FS_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libext2fs/ext2fs/ext2fsP.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libext2fs/ext2fs/ext2fsP.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,191 @@ +/* + * ext2fsP.h --- private header file for ext2 library + * + * Copyright (C) 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#if HAVE_SYS_STAT_H +#include +#endif + +#include "ext2fs.h" + +#define EXT2FS_MAX_NESTED_LINKS 8 + +static inline int ext2fsP_is_disk_device(mode_t mode) +{ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + return S_ISBLK(mode) || S_ISCHR(mode); +#else + return S_ISBLK(mode); +#endif +} + +/* + * Badblocks list + */ +struct ext2_struct_u32_list { + int magic; + int num; + int size; + __u32 *list; + int badblocks_flags; +}; + +struct ext2_struct_u32_iterate { + int magic; + ext2_u32_list bb; + int ptr; +}; + + +/* + * Directory block iterator definition + */ +struct ext2_struct_dblist { + int magic; + ext2_filsys fs; + unsigned long long size; + unsigned long long count; + int sorted; + struct ext2_db_entry2 * list; +}; + +/* + * For directory iterators + */ +struct dir_context { + ext2_ino_t dir; + int flags; + char *buf; + unsigned int buflen; + int (*func)(ext2_ino_t dir, + int entry, + struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data); + void *priv_data; + errcode_t errcode; +}; + +/* + * Inode cache structure + */ +struct ext2_inode_cache { + void * buffer; + blk64_t buffer_blk; + int cache_last; + unsigned int cache_size; + int refcount; + struct ext2_inode_cache_ent *cache; +}; + +struct ext2_inode_cache_ent { + ext2_ino_t ino; + struct ext2_inode *inode; +}; + +/* Function prototypes */ + +extern int ext2fs_process_dir_block(ext2_filsys fs, + blk64_t *blocknr, + e2_blkcnt_t blockcnt, + blk64_t ref_block, + int ref_offset, + void *priv_data); + +extern errcode_t ext2fs_inline_data_ea_remove(ext2_filsys fs, ext2_ino_t ino); +extern errcode_t ext2fs_inline_data_expand(ext2_filsys fs, ext2_ino_t ino); +extern int ext2fs_inline_data_dir_iterate(ext2_filsys fs, + ext2_ino_t ino, + void *priv_data); + +/* Generic numeric progress meter */ + +struct ext2fs_numeric_progress_struct { + __u64 max; + int log_max; + int skip_progress; +}; + +/* + * progress callback functions + */ +struct ext2fs_progress_ops { + void (*init)(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + const char *label, __u64 max); + void (*update)(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + __u64 val); + void (*close)(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + const char *message); +}; + +extern struct ext2fs_progress_ops ext2fs_numeric_progress_ops; + +extern void ext2fs_numeric_progress_init(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + const char *label, __u64 max); +extern void ext2fs_numeric_progress_update(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + __u64 val); +extern void ext2fs_numeric_progress_close(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + const char *message); + +/* + * 64-bit bitmap support + */ + +extern errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic, + int type, __u64 start, __u64 end, + __u64 real_end, + const char * description, + ext2fs_generic_bitmap *bmap); + +extern void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap); + +extern errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap *dest); + +extern errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap, + __u64 new_end, + __u64 new_real_end); +extern errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap, + errcode_t neq, + __u64 end, __u64 *oend); +extern int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 arg); +extern int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 arg); +extern int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 arg); +extern errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bitmap, + __u64 start, unsigned int num, + void *in); +extern errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bitmap, + __u64 start, unsigned int num, + void *out); +extern void ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap,const char *func); + +extern int ext2fs_mem_is_zero(const char *mem, size_t len); + +extern int ext2fs_file_block_offset_too_big(ext2_filsys fs, + struct ext2_inode *inode, + blk64_t offset); + +/* atexit support */ +typedef void (*ext2_exit_fn)(void *); +errcode_t ext2fs_add_exit_fn(ext2_exit_fn fn, void *data); +errcode_t ext2fs_remove_exit_fn(ext2_exit_fn fn, void *data); + +#define EXT2FS_BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2*!!(cond)])) diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libext2fs/ext2fs/ext3_extents.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libext2fs/ext2fs/ext3_extents.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2003,2004 Cluster File Systems, Inc, info@clusterfs.com + * Written by Alex Tomas + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _LINUX_EXT3_EXTENTS +#define _LINUX_EXT3_EXTENTS + +/* + * ext3_inode has i_block array (total 60 bytes) + * first 4 bytes are used to store: + * - tree depth (0 mean there is no tree yet. all extents in the inode) + * - number of alive extents in the inode + */ + +/* + * This is extent tail on-disk structure. + * All other extent structures are 12 bytes long. It turns out that + * block_size % 12 >= 4 for at least all powers of 2 greater than 512, which + * covers all valid ext4 block sizes. Therefore, this tail structure can be + * crammed into the end of the block without having to rebalance the tree. + */ +struct ext3_extent_tail { + __le32 et_checksum; /* crc32c(uuid+inum+extent_block) */ +}; + +/* + * this is extent on-disk structure + * it's used at the bottom of the tree + */ +struct ext3_extent { + __le32 ee_block; /* first logical block extent covers */ + __le16 ee_len; /* number of blocks covered by extent */ + __le16 ee_start_hi; /* high 16 bits of physical block */ + __le32 ee_start; /* low 32 bigs of physical block */ +}; + +/* + * this is index on-disk structure + * it's used at all the levels, but the bottom + */ +struct ext3_extent_idx { + __le32 ei_block; /* index covers logical blocks from 'block' */ + __le32 ei_leaf; /* pointer to the physical block of the next * + * level. leaf or next index could bet here */ + __le16 ei_leaf_hi; /* high 16 bits of physical block */ + __le16 ei_unused; +}; + +/* + * each block (leaves and indexes), even inode-stored has header + */ +struct ext3_extent_header { + __le16 eh_magic; /* probably will support different formats */ + __le16 eh_entries; /* number of valid entries */ + __le16 eh_max; /* capacity of store in entries */ + __le16 eh_depth; /* has tree real underlying blocks? */ + __le32 eh_generation; /* generation of the tree */ +}; + +#define EXT3_EXT_MAGIC 0xf30a + +/* + * array of ext3_ext_path contains path to some extent + * creation/lookup routines use it for traversal/splitting/etc + * truncate uses it to simulate recursive walking + */ +struct ext3_ext_path { + __u32 p_block; + __u16 p_depth; + struct ext3_extent *p_ext; + struct ext3_extent_idx *p_idx; + struct ext3_extent_header *p_hdr; + struct buffer_head *p_bh; +}; + +/* + * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an + * initialized extent. This is 2^15 and not (2^16 - 1), since we use the + * MSB of ee_len field in the extent datastructure to signify if this + * particular extent is an initialized extent or an uninitialized (i.e. + * preallocated). + * EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an + * uninitialized extent. + * If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an + * uninitialized one. In other words, if MSB of ee_len is set, it is an + * uninitialized extent with only one special scenario when ee_len = 0x8000. + * In this case we can not have an uninitialized extent of zero length and + * thus we make it as a special case of initialized extent with 0x8000 length. + * This way we get better extent-to-group alignment for initialized extents. + * Hence, the maximum number of blocks we can have in an *initialized* + * extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767). + */ +#define EXT_INIT_MAX_LEN (1UL << 15) +#define EXT_UNINIT_MAX_LEN (EXT_INIT_MAX_LEN - 1) +#define EXT_MAX_EXTENT_LBLK (((__u64) 1 << 32) - 1) +#define EXT_MAX_EXTENT_PBLK (((__u64) 1 << 48) - 1) + +#define EXT_FIRST_EXTENT(__hdr__) \ + ((struct ext3_extent *) (((char *) (__hdr__)) + \ + sizeof(struct ext3_extent_header))) +#define EXT_FIRST_INDEX(__hdr__) \ + ((struct ext3_extent_idx *) (((char *) (__hdr__)) + \ + sizeof(struct ext3_extent_header))) +#define EXT_HAS_FREE_INDEX(__path__) \ + (ext2fs_le16_to_cpu((__path__)->p_hdr->eh_entries) < \ + ext2fs_le16_to_cpu((__path__)->p_hdr->eh_max)) +#define EXT_LAST_EXTENT(__hdr__) \ + (EXT_FIRST_EXTENT((__hdr__)) + \ + ext2fs_le16_to_cpu((__hdr__)->eh_entries) - 1) +#define EXT_LAST_INDEX(__hdr__) \ + (EXT_FIRST_INDEX((__hdr__)) + \ + ext2fs_le16_to_cpu((__hdr__)->eh_entries) - 1) +#define EXT_MAX_EXTENT(__hdr__) \ + (EXT_FIRST_EXTENT((__hdr__)) + \ + ext2fs_le16_to_cpu((__hdr__)->eh_max) - 1) +#define EXT_MAX_INDEX(__hdr__) \ + (EXT_FIRST_INDEX((__hdr__)) + \ + ext2fs_le16_to_cpu((__hdr__)->eh_max) - 1) + +#endif /* _LINUX_EXT3_EXTENTS */ + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libext2fs/ext2fs/ext4_acl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libext2fs/ext2fs/ext4_acl.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,62 @@ +/* + * Ext4's on-disk acl format. From linux/fs/ext4/acl.h + */ + +#define EXT4_ACL_VERSION 0x0001 + +/* 23.2.5 acl_tag_t values */ + +#define ACL_UNDEFINED_TAG (0x00) +#define ACL_USER_OBJ (0x01) +#define ACL_USER (0x02) +#define ACL_GROUP_OBJ (0x04) +#define ACL_GROUP (0x08) +#define ACL_MASK (0x10) +#define ACL_OTHER (0x20) + +/* 23.3.6 acl_type_t values */ + +#define ACL_TYPE_ACCESS (0x8000) +#define ACL_TYPE_DEFAULT (0x4000) + +/* 23.2.7 ACL qualifier constants */ + +#define ACL_UNDEFINED_ID ((id_t)-1) + +typedef struct { + __le16 e_tag; + __le16 e_perm; + __le32 e_id; + } ext4_acl_entry; + +typedef struct { + __le16 e_tag; + __le16 e_perm; +} ext4_acl_entry_short; + +typedef struct { + __le32 a_version; +} ext4_acl_header; + + +/* Supported ACL a_version fields */ + #define POSIX_ACL_XATTR_VERSION 0x0002 + +typedef struct { + __le16 e_tag; + __le16 e_perm; + __le32 e_id; +} posix_acl_xattr_entry; + +typedef struct { + __le32 a_version; +#if __GNUC_PREREQ (4, 8) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#endif + posix_acl_xattr_entry a_entries[0]; +#if __GNUC_PREREQ (4, 8) +#pragma GCC diagnostic pop +#endif +} posix_acl_xattr_header; + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libext2fs/ext2fs/hashmap.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libext2fs/ext2fs/hashmap.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,54 @@ +#ifndef HASHMAP_H +# define HASHMAP_H + +# include +# include + +#ifndef __GNUC_PREREQ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +#define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +#define __GNUC_PREREQ(maj, min) 0 +#endif +#endif + +struct ext2fs_hashmap { + uint32_t size; + uint32_t(*hash)(const void *key, size_t len); + void(*free)(void*); + struct ext2fs_hashmap_entry *first; + struct ext2fs_hashmap_entry *last; + struct ext2fs_hashmap_entry { + void *data; + const void *key; + size_t key_len; + struct ext2fs_hashmap_entry *next; + struct ext2fs_hashmap_entry *list_next; + struct ext2fs_hashmap_entry *list_prev; +#if __GNUC_PREREQ (4, 8) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#endif + } *entries[0]; +#if __GNUC_PREREQ (4, 8) +#pragma GCC diagnostic pop +#endif +}; + +struct ext2fs_hashmap *ext2fs_hashmap_create( + uint32_t(*hash_fct)(const void*, size_t), + void(*free_fct)(void*), size_t size); +void ext2fs_hashmap_add(struct ext2fs_hashmap *h, void *data, const void *key, + size_t key_len); +void *ext2fs_hashmap_lookup(struct ext2fs_hashmap *h, const void *key, + size_t key_len); +void *ext2fs_hashmap_iter_in_order(struct ext2fs_hashmap *h, + struct ext2fs_hashmap_entry **it); +void ext2fs_hashmap_del(struct ext2fs_hashmap *h, + struct ext2fs_hashmap_entry *e); +void ext2fs_hashmap_free(struct ext2fs_hashmap *h); + +uint32_t ext2fs_djb2_hash(const void *str, size_t size); + +#endif /* !HASHMAP_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libext2fs/ext2fs/kernel-jbd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libext2fs/ext2fs/kernel-jbd.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,461 @@ +/* + * linux/include/linux/jbd.h + * + * Written by Stephen C. Tweedie + * + * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Definitions for transaction data structures for the buffer cache + * filesystem journaling support. + */ + +#ifndef _LINUX_JBD_H +#define _LINUX_JBD_H + +#include "jfs_compat.h" +#define JFS_DEBUG +#define jfs_debug jbd_debug + +#ifndef __GNUC__ +#define __FUNCTION__ "" +#endif + +#define journal_oom_retry 1 + +#ifdef __STDC__ +#ifdef CONFIG_JBD_DEBUG +/* + * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal + * consistency checks. By default we don't do this unless + * CONFIG_JBD_DEBUG is on. + */ +#define JBD_EXPENSIVE_CHECKING +extern int journal_enable_debug; + +#define jbd_debug(n, f, a...) \ + do { \ + if ((n) <= journal_enable_debug) { \ + printk (KERN_DEBUG "(%s, %d): %s: ", \ + __FILE__, __LINE__, __FUNCTION__); \ + printk (f, ## a); \ + } \ + } while (0) +#else +#ifdef __GNUC__ +#if defined(__KERNEL__) || !defined(CONFIG_JBD_DEBUG) +#define jbd_debug(f, a...) /**/ +#else +extern int journal_enable_debug; +#define jbd_debug(n, f, a...) \ + do { \ + if ((n) <= journal_enable_debug) { \ + printf("(%s, %d): %s: ", \ + __FILE__, __LINE__, __func__); \ + printf(f, ## a); \ + } \ + } while (0) +#endif /*__KERNEL__ */ +#else +#define jbd_debug(f, ...) /**/ +#endif +#endif +#else +#define jbd_debug(x) /* AIX doesn't do STDC */ +#endif + +extern void * __jbd_kmalloc (char *where, size_t size, int flags, int retry); +#define jbd_kmalloc(size, flags) \ + __jbd_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry) +#define jbd_rep_kmalloc(size, flags) \ + __jbd_kmalloc(__FUNCTION__, (size), (flags), 1) + +#define JFS_MIN_JOURNAL_BLOCKS 1024 + +/* + * Internal structures used by the logging mechanism: + */ + +#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */ + +/* + * On-disk structures + */ + +/* + * Descriptor block types: + */ + +#define JFS_DESCRIPTOR_BLOCK 1 +#define JFS_COMMIT_BLOCK 2 +#define JFS_SUPERBLOCK_V1 3 +#define JFS_SUPERBLOCK_V2 4 +#define JFS_REVOKE_BLOCK 5 + +/* + * Standard header for all descriptor blocks: + */ +typedef struct journal_header_s +{ + __u32 h_magic; + __u32 h_blocktype; + __u32 h_sequence; +} journal_header_t; + +/* + * Checksum types. + */ +#define JBD2_CRC32_CHKSUM 1 +#define JBD2_MD5_CHKSUM 2 +#define JBD2_SHA1_CHKSUM 3 +#define JBD2_CRC32C_CHKSUM 4 + +#define JBD2_CRC32_CHKSUM_SIZE 4 + +#define JBD2_CHECKSUM_BYTES (32 / sizeof(__u32)) +/* + * Commit block header for storing transactional checksums: + * + * NOTE: If FEATURE_COMPAT_CHECKSUM (checksum v1) is set, the h_chksum* + * fields are used to store a checksum of the descriptor and data blocks. + * + * If FEATURE_INCOMPAT_CSUM_V2 (checksum v2) is set, then the h_chksum + * field is used to store crc32c(uuid+commit_block). Each journal metadata + * block gets its own checksum, and data block checksums are stored in + * journal_block_tag (in the descriptor). The other h_chksum* fields are + * not used. + * + * If FEATURE_INCOMPAT_CSUM_V3 is set, the descriptor block uses + * journal_block_tag3_t to store a full 32-bit checksum. Everything else + * is the same as v2. + * + * Checksum v1, v2, and v3 are mutually exclusive features. + */ +struct commit_header { + __u32 h_magic; + __u32 h_blocktype; + __u32 h_sequence; + unsigned char h_chksum_type; + unsigned char h_chksum_size; + unsigned char h_padding[2]; + __u32 h_chksum[JBD2_CHECKSUM_BYTES]; + __u64 h_commit_sec; + __u32 h_commit_nsec; +}; + +/* + * The block tag: used to describe a single buffer in the journal + */ +typedef struct journal_block_tag3_s +{ + __u32 t_blocknr; /* The on-disk block number */ + __u32 t_flags; /* See below */ + __u32 t_blocknr_high; /* most-significant high 32bits. */ + __u32 t_checksum; /* crc32c(uuid+seq+block) */ +} journal_block_tag3_t; + +typedef struct journal_block_tag_s +{ + __u32 t_blocknr; /* The on-disk block number */ + __u16 t_checksum; /* truncated crc32c(uuid+seq+block) */ + __u16 t_flags; /* See below */ + __u32 t_blocknr_high; /* most-significant high 32bits. */ +} journal_block_tag_t; + +/* Tail of descriptor block, for checksumming */ +struct journal_block_tail { + __be32 t_checksum; +}; + +/* + * The revoke descriptor: used on disk to describe a series of blocks to + * be revoked from the log + */ +typedef struct journal_revoke_header_s +{ + journal_header_t r_header; + int r_count; /* Count of bytes used in the block */ +} journal_revoke_header_t; + +/* Tail of revoke block, for checksumming */ +struct journal_revoke_tail { + __be32 r_checksum; +}; + +/* Definitions for the journal tag flags word: */ +#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */ +#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */ +#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */ +#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */ + + +#define UUID_SIZE 16 +#define JFS_USERS_MAX 48 +#define JFS_USERS_SIZE (UUID_SIZE * JFS_USERS_MAX) +/* + * The journal superblock. All fields are in big-endian byte order. + */ +typedef struct journal_superblock_s +{ +/* 0x0000 */ + journal_header_t s_header; + +/* 0x000C */ + /* Static information describing the journal */ + __u32 s_blocksize; /* journal device blocksize */ + __u32 s_maxlen; /* total blocks in journal file */ + __u32 s_first; /* first block of log information */ + +/* 0x0018 */ + /* Dynamic information describing the current state of the log */ + __u32 s_sequence; /* first commit ID expected in log */ + __u32 s_start; /* blocknr of start of log */ + +/* 0x0020 */ + /* Error value, as set by journal_abort(). */ + __s32 s_errno; + +/* 0x0024 */ + /* Remaining fields are only valid in a version-2 superblock */ + __u32 s_feature_compat; /* compatible feature set */ + __u32 s_feature_incompat; /* incompatible feature set */ + __u32 s_feature_ro_compat; /* readonly-compatible feature set */ +/* 0x0030 */ + __u8 s_uuid[16]; /* 128-bit uuid for journal */ + +/* 0x0040 */ + __u32 s_nr_users; /* Nr of filesystems sharing log */ + + __u32 s_dynsuper; /* Blocknr of dynamic superblock copy*/ + +/* 0x0048 */ + __u32 s_max_transaction; /* Limit of journal blocks per trans.*/ + __u32 s_max_trans_data; /* Limit of data blocks per trans. */ + +/* 0x0050 */ + __u8 s_checksum_type; /* checksum type */ + __u8 s_padding2[3]; + __u32 s_padding[42]; + __u32 s_checksum; /* crc32c(superblock) */ + +/* 0x0100 */ + __u8 s_users[JFS_USERS_SIZE]; /* ids of all fs'es sharing the log */ + +/* 0x0400 */ +} journal_superblock_t; + +#define JFS_HAS_COMPAT_FEATURE(j,mask) \ + ((j)->j_format_version >= 2 && \ + ((j)->j_superblock->s_feature_compat & ext2fs_cpu_to_be32((mask)))) +#define JFS_HAS_RO_COMPAT_FEATURE(j,mask) \ + ((j)->j_format_version >= 2 && \ + ((j)->j_superblock->s_feature_ro_compat & ext2fs_cpu_to_be32((mask)))) +#define JFS_HAS_INCOMPAT_FEATURE(j,mask) \ + ((j)->j_format_version >= 2 && \ + ((j)->j_superblock->s_feature_incompat & ext2fs_cpu_to_be32((mask)))) + +#define JFS_FEATURE_COMPAT_CHECKSUM 0x00000001 + +#define JFS_FEATURE_INCOMPAT_REVOKE 0x00000001 +#define JFS_FEATURE_INCOMPAT_64BIT 0x00000002 +#define JFS_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004 +#define JFS_FEATURE_INCOMPAT_CSUM_V2 0x00000008 +#define JFS_FEATURE_INCOMPAT_CSUM_V3 0x00000010 + +/* Features known to this kernel version: */ +#define JFS_KNOWN_COMPAT_FEATURES 0 +#define JFS_KNOWN_ROCOMPAT_FEATURES 0 +#define JFS_KNOWN_INCOMPAT_FEATURES (JFS_FEATURE_INCOMPAT_REVOKE|\ + JFS_FEATURE_INCOMPAT_ASYNC_COMMIT|\ + JFS_FEATURE_INCOMPAT_64BIT|\ + JFS_FEATURE_INCOMPAT_CSUM_V2|\ + JFS_FEATURE_INCOMPAT_CSUM_V3) + +#ifdef NO_INLINE_FUNCS +extern size_t journal_tag_bytes(journal_t *journal); +extern int journal_has_csum_v2or3(journal_t *journal); +extern int tid_gt(tid_t x, tid_t y) EXT2FS_ATTR((unused)); +extern int tid_geq(tid_t x, tid_t y) EXT2FS_ATTR((unused)); +#endif + +#if (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS)) +#ifdef E2FSCK_INCLUDE_INLINE_FUNCS +#if (__STDC_VERSION__ >= 199901L) +#define _INLINE_ extern inline +#else +#define _INLINE_ inline +#endif +#else /* !E2FSCK_INCLUDE_INLINE FUNCS */ +#if (__STDC_VERSION__ >= 199901L) +#define _INLINE_ inline +#else /* not C99 */ +#ifdef __GNUC__ +#define _INLINE_ extern __inline__ +#else /* For Watcom C */ +#define _INLINE_ extern inline +#endif /* __GNUC__ */ +#endif /* __STDC_VERSION__ >= 199901L */ +#endif /* INCLUDE_INLINE_FUNCS */ + +/* journal feature predicate functions */ +#define JFS_FEATURE_COMPAT_FUNCS(name, flagname) \ +_INLINE_ int jfs_has_feature_##name(journal_t *j); \ +_INLINE_ int jfs_has_feature_##name(journal_t *j) \ +{ \ + return ((j)->j_format_version >= 2 && \ + ((j)->j_superblock->s_feature_compat & \ + ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_##flagname)) != 0); \ +} \ +_INLINE_ void jfs_set_feature_##name(journal_t *j); \ +_INLINE_ void jfs_set_feature_##name(journal_t *j) \ +{ \ + (j)->j_superblock->s_feature_compat |= \ + ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_##flagname); \ +} \ +_INLINE_ void jfs_clear_feature_##name(journal_t *j); \ +_INLINE_ void jfs_clear_feature_##name(journal_t *j) \ +{ \ + (j)->j_superblock->s_feature_compat &= \ + ~ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_##flagname); \ +} + +#define JFS_FEATURE_RO_COMPAT_FUNCS(name, flagname) \ +_INLINE_ int jfs_has_feature_##name(journal_t *j); \ +_INLINE_ int jfs_has_feature_##name(journal_t *j) \ +{ \ + return ((j)->j_format_version >= 2 && \ + ((j)->j_superblock->s_feature_ro_compat & \ + ext2fs_cpu_to_be32(JFS_FEATURE_RO_COMPAT_##flagname)) != 0); \ +} \ +_INLINE_ void jfs_set_feature_##name(journal_t *j); \ +_INLINE_ void jfs_set_feature_##name(journal_t *j) \ +{ \ + (j)->j_superblock->s_feature_ro_compat |= \ + ext2fs_cpu_to_be32(JFS_FEATURE_RO_COMPAT_##flagname); \ +} \ +_INLINE_ void jfs_clear_feature_##name(journal_t *j); \ +_INLINE_ void jfs_clear_feature_##name(journal_t *j) \ +{ \ + (j)->j_superblock->s_feature_ro_compat &= \ + ~ext2fs_cpu_to_be32(JFS_FEATURE_RO_COMPAT_##flagname); \ +} + +#define JFS_FEATURE_INCOMPAT_FUNCS(name, flagname) \ +_INLINE_ int jfs_has_feature_##name(journal_t *j); \ +_INLINE_ int jfs_has_feature_##name(journal_t *j) \ +{ \ + return ((j)->j_format_version >= 2 && \ + ((j)->j_superblock->s_feature_incompat & \ + ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_##flagname)) != 0); \ +} \ +_INLINE_ void jfs_set_feature_##name(journal_t *j); \ +_INLINE_ void jfs_set_feature_##name(journal_t *j) \ +{ \ + (j)->j_superblock->s_feature_incompat |= \ + ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_##flagname); \ +} \ +_INLINE_ void jfs_clear_feature_##name(journal_t *j); \ +_INLINE_ void jfs_clear_feature_##name(journal_t *j) \ +{ \ + (j)->j_superblock->s_feature_incompat &= \ + ~ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_##flagname); \ +} + +#else +#define JFS_FEATURE_COMPAT_FUNCS(name, flagname) \ +extern int jfs_has_feature_##name(journal_t *j); \ +extern void jfs_set_feature_##name(journal_t *j); \ +extern void jfs_clear_feature_##name(journal_t *j); + +#define JFS_FEATURE_RO_COMPAT_FUNCS(name, flagname) \ +extern int jfs_has_feature_##name(journal_t *j); \ +extern void jfs_set_feature_##name(journal_t *j); \ +extern void jfs_clear_feature_##name(journal_t *j); + +#define JFS_FEATURE_INCOMPAT_FUNCS(name, flagname) \ +extern int jfs_has_feature_##name(journal_t *j); \ +extern void jfs_set_feature_##name(journal_t *j); \ +extern void jfs_clear_feature_##name(journal_t *j); + +#endif /* (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS)) */ + +JFS_FEATURE_COMPAT_FUNCS(checksum, CHECKSUM) + +JFS_FEATURE_INCOMPAT_FUNCS(revoke, REVOKE) +JFS_FEATURE_INCOMPAT_FUNCS(64bit, 64BIT) +JFS_FEATURE_INCOMPAT_FUNCS(async_commit, ASYNC_COMMIT) +JFS_FEATURE_INCOMPAT_FUNCS(csum2, CSUM_V2) +JFS_FEATURE_INCOMPAT_FUNCS(csum3, CSUM_V3) + +#if (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS)) +/* + * helper functions to deal with 32 or 64bit block numbers. + */ +_INLINE_ size_t journal_tag_bytes(journal_t *journal) +{ + size_t sz; + + if (jfs_has_feature_csum3(journal)) + return sizeof(journal_block_tag3_t); + + sz = sizeof(journal_block_tag_t); + + if (jfs_has_feature_csum2(journal)) + sz += sizeof(__u16); + + if (jfs_has_feature_64bit(journal)) + return sz; + + return sz - sizeof(__u32); +} + +_INLINE_ int journal_has_csum_v2or3(journal_t *journal) +{ + if (jfs_has_feature_csum2(journal) || jfs_has_feature_csum3(journal)) + return 1; + + return 0; +} + +/* Comparison functions for transaction IDs: perform comparisons using + * modulo arithmetic so that they work over sequence number wraps. */ + +_INLINE_ int tid_gt(tid_t x, tid_t y) +{ + int difference = (x - y); + return (difference > 0); +} + +_INLINE_ int tid_geq(tid_t x, tid_t y) +{ + int difference = (x - y); + return (difference >= 0); +} +#endif /* (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS)) */ + +#undef _INLINE_ + +extern int journal_blocks_per_page(struct inode *inode); + +/* + * Definitions which augment the buffer_head layer + */ + +/* journaling buffer types */ +#define BJ_None 0 /* Not journaled */ +#define BJ_SyncData 1 /* Normal data: flush before commit */ +#define BJ_AsyncData 2 /* writepage data: wait on it before commit */ +#define BJ_Metadata 3 /* Normal journaled metadata */ +#define BJ_Forget 4 /* Buffer superceded by this transaction */ +#define BJ_IO 5 /* Buffer is for temporary IO use */ +#define BJ_Shadow 6 /* Buffer contents being shadowed to the log */ +#define BJ_LogCtl 7 /* Buffer contains log descriptors */ +#define BJ_Reserved 8 /* Buffer is reserved for access by journal */ +#define BJ_Types 9 + +extern int jbd_blocks_per_page(struct inode *inode); + +#endif /* _LINUX_JBD_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libsupport/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libsupport/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,7 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../../.. + +PKGNAME = libsupport +CONTRIB_HEADERS = 1 + +include $(L4DIR)/mk/include.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libsupport/support/quotaio.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libsupport/support/quotaio.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,265 @@ +/** quotaio.h + * + * Interface to the quota library. + * + * The quota library provides interface for creating and updating the quota + * files and the ext4 superblock fields. It supports the new VFS_V1 quota + * format. The quota library also provides support for keeping track of quotas + * in memory. + * The typical way to use the quota library is as follows: + * { + * quota_ctx_t qctx; + * + * quota_init_context(&qctx, fs, QUOTA_ALL_BIT); + * { + * quota_compute_usage(qctx); + * AND/OR + * quota_data_add/quota_data_sub/quota_data_inodes(); + * } + * quota_write_inode(qctx, USRQUOTA); + * quota_write_inode(qctx, GRPQUOTA); + * quota_release_context(&qctx); + * } + * + * This initial version does not support reading the quota files. This support + * will be added in near future. + * + * Aditya Kali + * Header of IO operations for quota utilities + * + * Jan Kara + */ + +#ifndef GUARD_QUOTAIO_H +#define GUARD_QUOTAIO_H + +#include +#include +#include + +#include "ext2fs/ext2_fs.h" +#include "ext2fs/ext2fs.h" +#include "dqblk_v2.h" + +typedef int64_t qsize_t; /* Type in which we store size limitations */ + +enum quota_type { + USRQUOTA = 0, + GRPQUOTA = 1, + PRJQUOTA = 2, + MAXQUOTAS = 3, +}; + +#if MAXQUOTAS > 32 +#error "cannot have more than 32 quota types to fit in qtype_bits" +#endif + +#define QUOTA_USR_BIT (1 << USRQUOTA) +#define QUOTA_GRP_BIT (1 << GRPQUOTA) +#define QUOTA_PRJ_BIT (1 << PRJQUOTA) +#define QUOTA_ALL_BIT (QUOTA_USR_BIT | QUOTA_GRP_BIT | QUOTA_PRJ_BIT) + +typedef struct quota_ctx *quota_ctx_t; +struct dict_t; + +struct quota_ctx { + ext2_filsys fs; + struct dict_t *quota_dict[MAXQUOTAS]; + struct quota_handle *quota_file[MAXQUOTAS]; +}; + +/* + * Definitions of magics and versions of current quota files + */ +#define INITQMAGICS {\ + 0xd9c01f11, /* USRQUOTA */\ + 0xd9c01927, /* GRPQUOTA */\ + 0xd9c03f14 /* PRJQUOTA */\ +} + +/* Size of blocks in which are counted size limits in generic utility parts */ +#define QUOTABLOCK_BITS 10 +#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) +#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) + +/* Quota format type IDs */ +#define QFMT_VFS_OLD 1 +#define QFMT_VFS_V0 2 +#define QFMT_VFS_V1 4 + +/* + * The following constants define the default amount of time given a user + * before the soft limits are treated as hard limits (usually resulting + * in an allocation failure). The timer is started when the user crosses + * their soft limit, it is reset when they go below their soft limit. + */ +#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ +#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ + +#define IOFL_INFODIRTY 0x01 /* Did info change? */ + +struct quotafile_ops; + +/* Generic information about quotafile */ +struct util_dqinfo { + time_t dqi_bgrace; /* Block grace time for given quotafile */ + time_t dqi_igrace; /* Inode grace time for given quotafile */ + union { + struct v2_mem_dqinfo v2_mdqi; + } u; /* Format specific info about quotafile */ +}; + +struct quota_file { + ext2_filsys fs; + ext2_ino_t ino; + ext2_file_t e2_file; +}; + +/* Structure for one opened quota file */ +struct quota_handle { + enum quota_type qh_type; /* Type of quotafile */ + int qh_fmt; /* Quotafile format */ + int qh_file_flags; + int qh_io_flags; /* IO flags for file */ + struct quota_file qh_qf; + unsigned int (*e2fs_read)(struct quota_file *qf, ext2_loff_t offset, + void *buf, unsigned int size); + unsigned int (*e2fs_write)(struct quota_file *qf, ext2_loff_t offset, + void *buf, unsigned int size); + struct quotafile_ops *qh_ops; /* Operations on quotafile */ + struct util_dqinfo qh_info; /* Generic quotafile info */ +}; + +/* Utility quota block */ +struct util_dqblk { + qsize_t dqb_ihardlimit; + qsize_t dqb_isoftlimit; + qsize_t dqb_curinodes; + qsize_t dqb_bhardlimit; + qsize_t dqb_bsoftlimit; + qsize_t dqb_curspace; + time_t dqb_btime; + time_t dqb_itime; + union { + struct v2_mem_dqblk v2_mdqb; + } u; /* Format specific dquot information */ +}; + +/* Structure for one loaded quota */ +struct dquot { + struct dquot *dq_next; /* Pointer to next dquot in the list */ + qid_t dq_id; /* ID dquot belongs to */ + int dq_flags; /* Some flags for utils */ + struct quota_handle *dq_h; /* Handle of quotafile for this dquot */ + struct util_dqblk dq_dqb; /* Parsed data of dquot */ +}; + +#define DQF_SEEN 0x0001 + +/* Structure of quotafile operations */ +struct quotafile_ops { + /* Check whether quotafile is in our format */ + int (*check_file) (struct quota_handle *h, int type, int fmt); + /* Open quotafile */ + int (*init_io) (struct quota_handle *h); + /* Create new quotafile */ + int (*new_io) (struct quota_handle *h); + /* Write all changes and close quotafile */ + int (*end_io) (struct quota_handle *h); + /* Write info about quotafile */ + int (*write_info) (struct quota_handle *h); + /* Read dquot into memory */ + struct dquot *(*read_dquot) (struct quota_handle *h, qid_t id); + /* Write given dquot to disk */ + int (*commit_dquot) (struct dquot *dquot); + /* Scan quotafile and call callback on every structure */ + int (*scan_dquots) (struct quota_handle *h, + int (*process_dquot) (struct dquot *dquot, + void *data), + void *data); + /* Function to print format specific file information */ + int (*report) (struct quota_handle *h, int verbose); +}; + +/* This might go into a special header file but that sounds a bit silly... */ +extern struct quotafile_ops quotafile_ops_meta; + +/* Open existing quotafile of given type (and verify its format) on given + * filesystem. */ +errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h, + ext2_ino_t qf_ino, enum quota_type type, + int fmt, int flags); + + +/* Create new quotafile of specified format on given filesystem */ +errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, + enum quota_type qtype, int fmt); + +/* Close quotafile */ +errcode_t quota_file_close(quota_ctx_t qctx, struct quota_handle *h); + +/* Get empty quota structure */ +struct dquot *get_empty_dquot(void); + +errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino); + +const char *quota_type2name(enum quota_type qtype); +ext2_ino_t quota_type2inum(enum quota_type qtype, struct ext2_super_block *); + +void update_grace_times(struct dquot *q); + +/* size for the buffer returned by quota_get_qf_name(); must be greater + than maxlen of extensions[] and fmtnames[] (plus 2) found in quotaio.c */ +#define QUOTA_NAME_LEN 16 + +const char *quota_get_qf_name(enum quota_type, int fmt, char *buf); + +/* In mkquota.c */ +errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, + unsigned int qtype_bits); +void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode_large *inode, + ext2_ino_t ino, int adjust); +void quota_data_add(quota_ctx_t qctx, struct ext2_inode_large *inode, + ext2_ino_t ino, qsize_t space); +void quota_data_sub(quota_ctx_t qctx, struct ext2_inode_large *inode, + ext2_ino_t ino, qsize_t space); +errcode_t quota_write_inode(quota_ctx_t qctx, enum quota_type qtype); +errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, + enum quota_type type); +errcode_t quota_compute_usage(quota_ctx_t qctx); +void quota_release_context(quota_ctx_t *qctx); +errcode_t quota_remove_inode(ext2_filsys fs, enum quota_type qtype); +int quota_file_exists(ext2_filsys fs, enum quota_type qtype); +void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, enum quota_type qtype); +errcode_t quota_compare_and_update(quota_ctx_t qctx, enum quota_type qtype, + int *usage_inconsistent); +int parse_quota_opts(const char *opts, int (*func)(char *)); + +/* parse_qtype.c */ +int parse_quota_types(const char *in_str, unsigned int *qtype_bits, + char **err_token); + +/* + * Return pointer to reserved inode field in superblock for given quota type. + * + * This allows the caller to get or set the quota inode by type without the + * need for the quota array to be contiguous in the superblock. + */ +static inline ext2_ino_t *quota_sb_inump(struct ext2_super_block *sb, + enum quota_type qtype) +{ + switch (qtype) { + case USRQUOTA: + return &sb->s_usr_quota_inum; + case GRPQUOTA: + return &sb->s_grp_quota_inum; + case PRJQUOTA: + return &sb->s_prj_quota_inum; + default: + return NULL; + } + + return NULL; +} + +#endif /* GUARD_QUOTAIO_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libuuid/uuid/uuid.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libuuid/uuid/uuid.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,103 @@ +/* + * Public include file for the UUID library + * + * Copyright (C) 1996, 1997, 1998 Theodore Ts'o. + * + * %Begin-Header% + * 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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 name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#ifndef _UUID_UUID_H +#define _UUID_UUID_H + +#include +#ifndef _WIN32 +#include +#endif +#include + +typedef unsigned char uuid_t[16]; + +/* UUID Variant definitions */ +#define UUID_VARIANT_NCS 0 +#define UUID_VARIANT_DCE 1 +#define UUID_VARIANT_MICROSOFT 2 +#define UUID_VARIANT_OTHER 3 + +/* UUID Type definitions */ +#define UUID_TYPE_DCE_TIME 1 +#define UUID_TYPE_DCE_RANDOM 4 + +/* Allow UUID constants to be defined */ +#ifdef __GNUC__ +#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \ + static const uuid_t name __attribute__ ((unused)) = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15} +#else +#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \ + static const uuid_t name = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15} +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* clear.c */ +void uuid_clear(uuid_t uu); + +/* compare.c */ +int uuid_compare(const uuid_t uu1, const uuid_t uu2); + +/* copy.c */ +void uuid_copy(uuid_t dst, const uuid_t src); + +/* gen_uuid.c */ +void uuid_generate(uuid_t out); +void uuid_generate_random(uuid_t out); +void uuid_generate_time(uuid_t out); + +/* isnull.c */ +int uuid_is_null(const uuid_t uu); + +/* parse.c */ +int uuid_parse(const char *in, uuid_t uu); + +/* unparse.c */ +void uuid_unparse(const uuid_t uu, char *out); +void uuid_unparse_lower(const uuid_t uu, char *out); +void uuid_unparse_upper(const uuid_t uu, char *out); + +/* uuid_time.c */ +time_t uuid_time(const uuid_t uu, struct timeval *ret_tv); +int uuid_type(const uuid_t uu); +int uuid_variant(const uuid_t uu); + +#ifdef __cplusplus +} +#endif + +#endif /* _UUID_UUID_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/include/libuuid/uuid/uuid_types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/include/libuuid/uuid/uuid_types.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,50 @@ +/* + * If linux/types.h is already been included, assume it has defined + * everything we need. (cross fingers) Other header files may have + * also defined the types that we need. + */ +#if (!defined(_STDINT_H) && !defined(_UUID_STDINT_H)) +#define _UUID_STDINT_H + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +#if (4 == 8) +typedef int int64_t; +typedef unsigned int uint64_t; +#elif (4 == 8) +typedef long int64_t; +typedef unsigned long uint64_t; +#elif (8 == 8) +#if defined(__GNUC__) +typedef __signed__ long long int64_t; +#else +typedef signed long long int64_t; +#endif +typedef unsigned long long uint64_t; +#endif + +#if (4 == 2) +typedef int int16_t; +typedef unsigned int uint16_t; +#elif (2 == 2) +typedef short int16_t; +typedef unsigned short uint16_t; +#else + ?==error: undefined 16 bit type +#endif + +#if (4 == 4) +typedef int int32_t; +typedef unsigned int uint32_t; +#elif (4 == 4) +typedef long int32_t; +typedef unsigned long uint32_t; +#elif (2 == 4) +typedef short int32_t; +typedef unsigned short uint32_t; +#else + ?== error: undefined 32 bit type +#endif + +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,11 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../../.. + +TARGET := libuuid libblkid libsupport libet libe2p libext2fs + +include $(L4DIR)/mk/subdir.mk + +libblkid: libuuid +libsupport: libblkid +libe2p: libet libsupport +libext2fs: libet libe2p diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/config.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,63 @@ +#include + +/* Definitions based on the current status of L4Re. */ + +#define HAVE_ERRNO_H 1 +#define HAVE_EXT2_IOCTLS 1 +#define HAVE_FALLOCATE 1 +#define HAVE_FALLOCATE64 1 +#define HAVE_FCNTL 1 +#define HAVE_FSTAT64 1 +#define HAVE_FSYNC 1 +#define HAVE_GETHOSTNAME 1 +#define HAVE_GETPAGESIZE 1 +#define HAVE_LSEEK64 1 +#define HAVE_LSEEK64_PROTOTYPE 1 +#define HAVE_LSEEK64_PROTOTYPE 1 +#define HAVE_MALLOC_H 1 +#define HAVE_MEMALIGN 1 +#define HAVE_NETINET_IN_H 1 +#define HAVE_OPEN64 1 +#define HAVE_POSIX_MEMALIGN 1 +#define HAVE_PREAD 1 +#define HAVE_PREAD64 1 +#define HAVE_PREAD64 1 +#define HAVE_PWRITE 1 +#define HAVE_PWRITE64 1 +#define HAVE_PWRITE64 1 +#define HAVE_SECURE_GETENV 1 +#define HAVE_SRANDOM 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRNLEN 1 +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_SYS_MOUNT_H 1 +#define HAVE_SYS_RESOURCE_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_SYSMACROS_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_UNISTD_H 1 +#define HAVE_VALLOC 1 +#define TLS __thread + +#if 0 +#define HAVE_LINUX_FALLOC_H 1 +#define HAVE_LINUX_FD_H 1 +#define HAVE_LINUX_LOOP_H 1 +#define HAVE_LINUX_MAJOR_H 1 +#define HAVE_LINUX_TYPES_H 1 +#define HAVE_MNTENT_H 1 +#define HAVE_PRCTL 1 +#define HAVE_SETMNTENT 1 +#define HAVE_SYS_PRCTL_H 1 +#endif + +/* libext2fs metadata. */ + +#define VERSION "0.14.1" + +/* Machine-specific definitions. See and . */ + +#define SIZEOF_LONG (__WORDSIZE / 8) +#define SIZEOF_LONG_LONG 8 +#define SIZEOF_OFF_T (__WORDSIZE / 8) diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/config.h.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/config.h.in Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,899 @@ +/* lib/config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + +/* Define to 1 if debugging the blkid library */ +#undef CONFIG_BLKID_DEBUG + +/* Define to 1 to compile findfs */ +#undef CONFIG_BUILD_FINDFS + +/* Define to 1 if debugging ext3/4 journal code */ +#undef CONFIG_JBD_DEBUG + +/* Define to 1 to enable mmp support */ +#undef CONFIG_MMP + +/* Define to 1 to enable tdb support */ +#undef CONFIG_TDB + +/* Define to 1 if the testio I/O manager should be enabled */ +#undef CONFIG_TESTIO_DEBUG + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +#undef CRAY_STACKSEG_END + +/* Define to 1 if using `alloca.c'. */ +#undef C_ALLOCA + +/* Define to 1 to disable use of backtrace */ +#undef DISABLE_BACKTRACE + +/* Define to 1 to enable bitmap stats. */ +#undef ENABLE_BMAP_STATS + +/* Define to 1 to enable bitmap stats. */ +#undef ENABLE_BMAP_STATS_OPS + +/* 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 `add_key' function. */ +#undef HAVE_ADD_KEY + +/* Define to 1 if you have `alloca', as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#undef HAVE_ALLOCA_H + +/* Define to 1 if you have the `argz_count' function. */ +#undef HAVE_ARGZ_COUNT + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARGZ_H + +/* Define to 1 if you have the `argz_next' function. */ +#undef HAVE_ARGZ_NEXT + +/* Define to 1 if you have the `argz_stringify' function. */ +#undef HAVE_ARGZ_STRINGIFY + +/* Define to 1 if you have the `asprintf' function. */ +#undef HAVE_ASPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_ATTR_XATTR_H + +/* Define to 1 if you have the `backtrace' function. */ +#undef HAVE_BACKTRACE + +/* Define to 1 if you have the `blkid_probe_enable_partitions' function. */ +#undef HAVE_BLKID_PROBE_ENABLE_PARTITIONS + +/* Define to 1 if you have the `blkid_probe_get_topology' function. */ +#undef HAVE_BLKID_PROBE_GET_TOPOLOGY + +/* Define to 1 if the compiler understands __builtin_expect. */ +#undef HAVE_BUILTIN_EXPECT + +/* Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the + CoreFoundation framework. */ +#undef HAVE_CFLOCALECOPYCURRENT + +/* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in + the CoreFoundation framework. */ +#undef HAVE_CFPREFERENCESCOPYAPPVALUE + +/* Define to 1 if you have the `chflags' function. */ +#undef HAVE_CHFLAGS + +/* Define if the GNU dcgettext() function is already present or preinstalled. + */ +#undef HAVE_DCGETTEXT + +/* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you + don't. */ +#undef HAVE_DECL_FEOF_UNLOCKED + +/* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if + you don't. */ +#undef HAVE_DECL_FGETS_UNLOCKED + +/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you + don't. */ +#undef HAVE_DECL_GETC_UNLOCKED + +/* Define to 1 if you have the declaration of `_snprintf', and to 0 if you + don't. */ +#undef HAVE_DECL__SNPRINTF + +/* Define to 1 if you have the declaration of `_snwprintf', and to 0 if you + don't. */ +#undef HAVE_DECL__SNWPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_DIRENT_H + +/* Define to 1 if you have the `dlopen' function. */ +#undef HAVE_DLOPEN + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_EXECINFO_H + +/* Define to 1 if Ext2 ioctls present */ +#undef HAVE_EXT2_IOCTLS + +/* Define to 1 if you have the `fadvise64' function. */ +#undef HAVE_FADVISE64 + +/* Define to 1 if you have the `fallocate' function. */ +#undef HAVE_FALLOCATE + +/* Define to 1 if you have the `fallocate64' function. */ +#undef HAVE_FALLOCATE64 + +/* Define to 1 if you have the `fchown' function. */ +#undef HAVE_FCHOWN + +/* Define to 1 if you have the `fcntl' function. */ +#undef HAVE_FCNTL + +/* Define to 1 if you have the `fdatasync' function. */ +#undef HAVE_FDATASYNC + +/* Define to 1 if you have the header file. */ +#undef HAVE_FEATURES_H + +/* Define to 1 if you have the `fstat64' function. */ +#undef HAVE_FSTAT64 + +/* Define to 1 if you have the `fsync' function. */ +#undef HAVE_FSYNC + +/* Define to 1 if you have the `ftruncate64' function. */ +#undef HAVE_FTRUNCATE64 + +/* Define to 1 if you have the header file. */ +#undef HAVE_FUSE_H + +/* Define to 1 if you have the `futimes' function. */ +#undef HAVE_FUTIMES + +/* Define to 1 if you have the `fwprintf' function. */ +#undef HAVE_FWPRINTF + +/* Define to 1 if you have the `getcwd' function. */ +#undef HAVE_GETCWD + +/* Define to 1 if you have the `getdtablesize' function. */ +#undef HAVE_GETDTABLESIZE + +/* Define to 1 if you have the `getegid' function. */ +#undef HAVE_GETEGID + +/* Define to 1 if you have the `geteuid' function. */ +#undef HAVE_GETEUID + +/* Define to 1 if you have the `getgid' function. */ +#undef HAVE_GETGID + +/* Define to 1 if you have the `gethostname' function. */ +#undef HAVE_GETHOSTNAME + +/* Define to 1 if you have the `getmntinfo' function. */ +#undef HAVE_GETMNTINFO + +/* Define to 1 if you have the header file. */ +#undef HAVE_GETOPT_H + +/* Define to 1 if you have the `getpagesize' function. */ +#undef HAVE_GETPAGESIZE + +/* Define to 1 if you have the `getpwuid_r' function. */ +#undef HAVE_GETPWUID_R + +/* Define to 1 if you have the `getrlimit' function. */ +#undef HAVE_GETRLIMIT + +/* Define to 1 if you have the `getrusage' function. */ +#undef HAVE_GETRUSAGE + +/* Define if the GNU gettext() function is already present or preinstalled. */ +#undef HAVE_GETTEXT + +/* Define to 1 if you have the `getuid' function. */ +#undef HAVE_GETUID + +/* Define if you have the iconv() function and it works. */ +#undef HAVE_ICONV + +/* Define if you have the 'intmax_t' type in or . */ +#undef HAVE_INTMAX_T + +/* Define to 1 if the system has the type `intptr_t'. */ +#undef HAVE_INTPTR_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define if exists, doesn't clash with , and + declares uintmax_t. */ +#undef HAVE_INTTYPES_H_WITH_UINTMAX + +/* Define to 1 if you have the `jrand48' function. */ +#undef HAVE_JRAND48 + +/* Define to 1 if you have the `keyctl' function. */ +#undef HAVE_KEYCTL + +/* Define if you have and nl_langinfo(CODESET). */ +#undef HAVE_LANGINFO_CODESET + +/* Define if your file defines LC_MESSAGES. */ +#undef HAVE_LC_MESSAGES + +/* 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_FALLOC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_FD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_FSMAP_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_LOOP_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_MAJOR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_TYPES_H + +/* Define to 1 if you have the `llistxattr' function. */ +#undef HAVE_LLISTXATTR + +/* Define to 1 if you have the `llseek' function. */ +#undef HAVE_LLSEEK + +/* Define to 1 if llseek declared in unistd.h */ +#undef HAVE_LLSEEK_PROTOTYPE + +/* Define to 1 if the system has the type 'long long int'. */ +#undef HAVE_LONG_LONG_INT + +/* Define to 1 if you have the `lseek64' function. */ +#undef HAVE_LSEEK64 + +/* Define to 1 if lseek64 declared in unistd.h */ +#undef HAVE_LSEEK64_PROTOTYPE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MAGIC_H + +/* Define to 1 if you have the `mallinfo' function. */ +#undef HAVE_MALLINFO + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the `mbrtowc' function. */ +#undef HAVE_MBRTOWC + +/* Define to 1 if you have the `mbstowcs' function. */ +#undef HAVE_MBSTOWCS + +/* Define to 1 if you have the `memalign' function. */ +#undef HAVE_MEMALIGN + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `mempcpy' function. */ +#undef HAVE_MEMPCPY + +/* Define to 1 if you have the `mmap' function. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the header file. */ +#undef HAVE_MNTENT_H + +/* Define to 1 if you have the `msync' function. */ +#undef HAVE_MSYNC + +/* Define to 1 if you have the `munmap' function. */ +#undef HAVE_MUNMAP + +/* Define to 1 if you have the `nanosleep' function. */ +#undef HAVE_NANOSLEEP + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_DL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_H + +/* Define to 1 if you have the `newlocale' function. */ +#undef HAVE_NEWLOCALE + +/* Define to 1 if you have the `open64' function. */ +#undef HAVE_OPEN64 + +/* Define to 1 if optreset for getopt is present */ +#undef HAVE_OPTRESET + +/* Define to 1 if you have the `pathconf' function. */ +#undef HAVE_PATHCONF + +/* Define to 1 if you have the header file. */ +#undef HAVE_PATHS_H + +/* Define to 1 if you have the `posix_fadvise' function. */ +#undef HAVE_POSIX_FADVISE + +/* Define to 1 if you have the `posix_fadvise64' function. */ +#undef HAVE_POSIX_FADVISE64 + +/* Define to 1 if you have the `posix_memalign' function. */ +#undef HAVE_POSIX_MEMALIGN + +/* Define if your printf() function supports format strings with positions. */ +#undef HAVE_POSIX_PRINTF + +/* Define to 1 if you have the `prctl' function. */ +#undef HAVE_PRCTL + +/* Define to 1 if you have the `pread' function. */ +#undef HAVE_PREAD + +/* Define to 1 if you have the `pread64' function. */ +#undef HAVE_PREAD64 + +/* Define to 1 if you have the header file. */ +#undef HAVE_PTHREAD_H + +/* Define if the defines PTHREAD_MUTEX_RECURSIVE. */ +#undef HAVE_PTHREAD_MUTEX_RECURSIVE + +/* Define if the POSIX multithreading library has read/write locks. */ +#undef HAVE_PTHREAD_RWLOCK + +/* Define to 1 if you have the `putenv' function. */ +#undef HAVE_PUTENV + +/* Define to 1 if you have the `pwrite' function. */ +#undef HAVE_PWRITE + +/* Define to 1 if you have the `pwrite64' function. */ +#undef HAVE_PWRITE64 + +/* Define to 1 if dirent has d_reclen */ +#undef HAVE_RECLEN_DIRENT + +/* Define to 1 if if struct sockaddr contains sa_len */ +#undef HAVE_SA_LEN + +/* Define to 1 if you have the `secure_getenv' function. */ +#undef HAVE_SECURE_GETENV + +/* Define to 1 if you have the header file. */ +#undef HAVE_SEMAPHORE_H + +/* Define to 1 if sem_init() exists */ +#undef HAVE_SEM_INIT + +/* Define to 1 if you have the `setenv' function. */ +#undef HAVE_SETENV + +/* Define to 1 if you have the header file. */ +#undef HAVE_SETJMP_H + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the `setmntent' function. */ +#undef HAVE_SETMNTENT + +/* Define to 1 if you have the `setresgid' function. */ +#undef HAVE_SETRESGID + +/* Define to 1 if you have the `setresuid' function. */ +#undef HAVE_SETRESUID + +/* Define to 1 if you have the header file. */ +#undef HAVE_SIGNAL_H + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if you have the `srandom' function. */ +#undef HAVE_SRANDOM + +/* Define to 1 if struct stat has st_flags */ +#undef HAVE_STAT_FLAGS + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDARG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define if exists, doesn't clash with , and declares + uintmax_t. */ +#undef HAVE_STDINT_H_WITH_UINTMAX + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `stpcpy' function. */ +#undef HAVE_STPCPY + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* 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 `strnlen' function. */ +#undef HAVE_STRNLEN + +/* Define to 1 if you have the `strptime' function. */ +#undef HAVE_STRPTIME + +/* Define to 1 if you have the `strtoul' function. */ +#undef HAVE_STRTOUL + +/* Define to 1 if you have the `strtoull' function. */ +#undef HAVE_STRTOULL + +/* Define to 1 if `st_atim' is a member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_ATIM + +/* Define to 1 if you have the `symlink' function. */ +#undef HAVE_SYMLINK + +/* Define to 1 if you have the `sync_file_range' function. */ +#undef HAVE_SYNC_FILE_RANGE + +/* Define to 1 if you have the `sysconf' function. */ +#undef HAVE_SYSCONF + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_ACL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_DISKLABEL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_DISK_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FILE_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_KEY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MKDEV_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MMAN_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_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PRCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKIO_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_SYSCALL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SYSCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SYSMACROS_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_SYS_UN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_XATTR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TERMIOS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TERMIO_H + +/* Define to 1 if you have the `tsearch' function. */ +#undef HAVE_TSEARCH + +/* Define to 1 if ssize_t declared */ +#undef HAVE_TYPE_SSIZE_T + +/* Define if you have the 'uintmax_t' type in or . */ +#undef HAVE_UINTMAX_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if the system has the type 'unsigned long long int'. */ +#undef HAVE_UNSIGNED_LONG_LONG_INT + +/* Define to 1 if you have the `uselocale' function. */ +#undef HAVE_USELOCALE + +/* Define to 1 if you have the `usleep' function. */ +#undef HAVE_USLEEP + +/* Define to 1 if you have the `utime' function. */ +#undef HAVE_UTIME + +/* Define to 1 if you have the `utimes' function. */ +#undef HAVE_UTIMES + +/* Define to 1 if you have the header file. */ +#undef HAVE_UTIME_H + +/* Define to 1 if you have the `valloc' function. */ +#undef HAVE_VALLOC + +/* Define to 1 or 0, depending whether the compiler supports simple visibility + declarations. */ +#undef HAVE_VISIBILITY + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define if you have the 'wchar_t' type. */ +#undef HAVE_WCHAR_T + +/* Define to 1 if you have the `wcrtomb' function. */ +#undef HAVE_WCRTOMB + +/* Define to 1 if you have the `wcslen' function. */ +#undef HAVE_WCSLEN + +/* Define to 1 if you have the `wcsnlen' function. */ +#undef HAVE_WCSNLEN + +/* Define if you have the 'wint_t' type. */ +#undef HAVE_WINT_T + +/* Define to 1 if O_NOATIME works. */ +#undef HAVE_WORKING_O_NOATIME + +/* Define to 1 if O_NOFOLLOW works. */ +#undef HAVE_WORKING_O_NOFOLLOW + +/* Define to 1 if you have the `__fsetlocking' function. */ +#undef HAVE___FSETLOCKING + +/* Define to 1 if you have the `__secure_getenv' function. */ +#undef HAVE___SECURE_GETENV + +/* Define as const if the declaration of iconv() needs const. */ +#undef ICONV_CONST + +/* Define if integer division by zero raises signal SIGFPE. */ +#undef INTDIV0_RAISES_SIGFPE + +/* package name for gettext */ +#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 if exists and defines unusable PRI* macros. */ +#undef PRI_MACROS_BROKEN + +/* Define if the pthread_in_use() detection is hard. */ +#undef PTHREAD_IN_USE_DETECTION_HARD + +/* The size of `int', as computed by sizeof. */ +#undef SIZEOF_INT + +/* The size of `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of `long long', as computed by sizeof. */ +#undef SIZEOF_LONG_LONG + +/* The size of `off_t', as computed by sizeof. */ +#undef SIZEOF_OFF_T + +/* The size of `short', as computed by sizeof. */ +#undef SIZEOF_SHORT + +/* The size of `time_t', as computed by sizeof. */ +#undef SIZEOF_TIME_T + +/* Define as the maximum value of type 'size_t', if the system doesn't define + it. */ +#ifndef SIZE_MAX +# undef SIZE_MAX +#endif + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +#undef STACK_DIRECTION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* If the compiler supports a TLS storage class define it to that here */ +#undef TLS + +/* Define if the POSIX multithreading library can be used. */ +#undef USE_POSIX_THREADS + +/* Define if references to the POSIX multithreading library should be made + weak. */ +#undef USE_POSIX_THREADS_WEAK + +/* Define if the GNU Pth multithreading library can be used. */ +#undef USE_PTH_THREADS + +/* Define if references to the GNU Pth multithreading library should be made + weak. */ +#undef USE_PTH_THREADS_WEAK + +/* Define if the old Solaris multithreading library can be used. */ +#undef USE_SOLARIS_THREADS + +/* Define if references to the old Solaris multithreading library should be + made weak. */ +#undef USE_SOLARIS_THREADS_WEAK + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + +/* Define to 1 to build uuidd */ +#undef USE_UUIDD + +/* Define if the native Windows multithreading API can be used. */ +#undef USE_WINDOWS_THREADS + +/* version for gettext */ +#undef VERSION + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif + +/* Define to 1 if Apple Darwin libintl workaround is needed */ +#undef _INTL_REDIRECT_MACROS + +/* Define to 1 if on MINIX. */ +#undef _MINIX + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#undef _POSIX_1_SOURCE + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +#undef _POSIX_SOURCE + +/* Please see the Gnulib manual for how to use these macros. + + Suppress extern inline with HP-UX cc, as it appears to be broken; see + . + + Suppress extern inline with Sun C in standards-conformance mode, as it + mishandles inline functions that call each other. E.g., for 'inline void f + (void) { } inline void g (void) { f (); }', c99 incorrectly complains + 'reference to static identifier "f" in extern inline function'. + This bug was observed with Sun C 5.12 SunOS_i386 2011/11/16. + + Suppress the use of extern inline on Apple's platforms, as Libc at least + through Libc-825.26 (2013-04-09) is incompatible with it; see, e.g., + . + Perhaps Apple will fix this some day. */ +#if ((__GNUC__ \ + ? defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ \ + : (199901L <= __STDC_VERSION__ \ + && !defined __HP_cc \ + && !(defined __SUNPRO_C && __STDC__))) \ + && !defined __APPLE__) +# define _GL_INLINE inline +# define _GL_EXTERN_INLINE extern inline +#elif (2 < __GNUC__ + (7 <= __GNUC_MINOR__) && !defined __STRICT_ANSI__ \ + && !defined __APPLE__) +# if __GNUC_GNU_INLINE__ + /* __gnu_inline__ suppresses a GCC 4.2 diagnostic. */ +# define _GL_INLINE extern inline __attribute__ ((__gnu_inline__)) +# else +# define _GL_INLINE extern inline +# endif +# define _GL_EXTERN_INLINE extern +#else +# define _GL_INLINE static _GL_UNUSED +# define _GL_EXTERN_INLINE static _GL_UNUSED +#endif + +#if 4 < __GNUC__ + (6 <= __GNUC_MINOR__) +# if defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ +# define _GL_INLINE_HEADER_CONST_PRAGMA +# else +# define _GL_INLINE_HEADER_CONST_PRAGMA \ + _Pragma ("GCC diagnostic ignored \"-Wsuggest-attribute=const\"") +# endif + /* Suppress GCC's bogus "no previous prototype for 'FOO'" + and "no previous declaration for 'FOO'" diagnostics, + when FOO is an inline function in the header; see + . */ +# define _GL_INLINE_HEADER_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wmissing-prototypes\"") \ + _Pragma ("GCC diagnostic ignored \"-Wmissing-declarations\"") \ + _GL_INLINE_HEADER_CONST_PRAGMA +# define _GL_INLINE_HEADER_END \ + _Pragma ("GCC diagnostic pop") +#else +# define _GL_INLINE_HEADER_BEGIN +# define _GL_INLINE_HEADER_END +#endif + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define as the type of the result of subtracting two pointers, if the system + doesn't define it. */ +#undef ptrdiff_t + +/* Define to `unsigned int' if does not define. */ +#undef size_t + +/* Define to unsigned long or unsigned long long if and + don't define. */ +#undef uintmax_t + +#include + + +#define __libc_lock_t gl_lock_t +#define __libc_lock_define gl_lock_define +#define __libc_lock_define_initialized gl_lock_define_initialized +#define __libc_lock_init gl_lock_init +#define __libc_lock_lock gl_lock_lock +#define __libc_lock_unlock gl_lock_unlock +#define __libc_lock_recursive_t gl_recursive_lock_t +#define __libc_lock_define_recursive gl_recursive_lock_define +#define __libc_lock_define_initialized_recursive gl_recursive_lock_define_initialized +#define __libc_lock_init_recursive gl_recursive_lock_init +#define __libc_lock_lock_recursive gl_recursive_lock_lock +#define __libc_lock_unlock_recursive gl_recursive_lock_unlock +#define glthread_in_use libintl_thread_in_use +#define glthread_lock_init_func libintl_lock_init_func +#define glthread_lock_lock_func libintl_lock_lock_func +#define glthread_lock_unlock_func libintl_lock_unlock_func +#define glthread_lock_destroy_func libintl_lock_destroy_func +#define glthread_rwlock_init_multithreaded libintl_rwlock_init_multithreaded +#define glthread_rwlock_init_func libintl_rwlock_init_func +#define glthread_rwlock_rdlock_multithreaded libintl_rwlock_rdlock_multithreaded +#define glthread_rwlock_rdlock_func libintl_rwlock_rdlock_func +#define glthread_rwlock_wrlock_multithreaded libintl_rwlock_wrlock_multithreaded +#define glthread_rwlock_wrlock_func libintl_rwlock_wrlock_func +#define glthread_rwlock_unlock_multithreaded libintl_rwlock_unlock_multithreaded +#define glthread_rwlock_unlock_func libintl_rwlock_unlock_func +#define glthread_rwlock_destroy_multithreaded libintl_rwlock_destroy_multithreaded +#define glthread_rwlock_destroy_func libintl_rwlock_destroy_func +#define glthread_recursive_lock_init_multithreaded libintl_recursive_lock_init_multithreaded +#define glthread_recursive_lock_init_func libintl_recursive_lock_init_func +#define glthread_recursive_lock_lock_multithreaded libintl_recursive_lock_lock_multithreaded +#define glthread_recursive_lock_lock_func libintl_recursive_lock_lock_func +#define glthread_recursive_lock_unlock_multithreaded libintl_recursive_lock_unlock_multithreaded +#define glthread_recursive_lock_unlock_func libintl_recursive_lock_unlock_func +#define glthread_recursive_lock_destroy_multithreaded libintl_recursive_lock_destroy_multithreaded +#define glthread_recursive_lock_destroy_func libintl_recursive_lock_destroy_func +#define glthread_once_func libintl_once_func +#define glthread_once_singlethreaded libintl_once_singlethreaded +#define glthread_once_multithreaded libintl_once_multithreaded + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,19 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../../.. + +TARGET = libblkid.a libblkid.so +PC_FILENAME = libblkid +SRC_C = \ + cache.c dev.c devname.c devno.c getsize.c llseek.c probe.c \ + read.c resolve.c save.c tag.c tst_types.c version.c + +REQUIRES_LIBS = libuuid + +PRIVATE_INCDIR += \ + $(PKGDIR)/lib $(PKGDIR)/lib/libblkid \ + $(PKGDIR)/include/libblkid \ + $(PKGDIR)/include/libuuid + +CONTRIB_INCDIR = libblkid + +include $(L4DIR)/mk/lib.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/blkidP.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/blkidP.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,204 @@ +/* + * blkidP.h - Internal interfaces for libblkid + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#ifndef _BLKID_BLKIDP_H +#define _BLKID_BLKIDP_H + +#include +#include +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif + +#include + +#include + +#ifdef __GNUC__ +#define __BLKID_ATTR(x) __attribute__(x) +#else +#define __BLKID_ATTR(x) +#endif + + +/* + * This describes the attributes of a specific device. + * We can traverse all of the tags by bid_tags (linking to the tag bit_names). + * The bid_label and bid_uuid fields are shortcuts to the LABEL and UUID tag + * values, if they exist. + */ +struct blkid_struct_dev +{ + struct list_head bid_devs; /* All devices in the cache */ + struct list_head bid_tags; /* All tags for this device */ + blkid_cache bid_cache; /* Dev belongs to this cache */ + char *bid_name; /* Device inode pathname */ + char *bid_type; /* Preferred device TYPE */ + int bid_pri; /* Device priority */ + dev_t bid_devno; /* Device major/minor number */ + time_t bid_time; /* Last update time of device */ + unsigned int bid_flags; /* Device status bitflags */ + char *bid_label; /* Shortcut to device LABEL */ + char *bid_uuid; /* Shortcut to binary UUID */ +}; + +#define BLKID_BID_FL_VERIFIED 0x0001 /* Device data validated from disk */ +#define BLKID_BID_FL_INVALID 0x0004 /* Device is invalid */ + +/* + * Each tag defines a NAME=value pair for a particular device. The tags + * are linked via bit_names for a single device, so that traversing the + * names list will get you a list of all tags associated with a device. + * They are also linked via bit_values for all devices, so one can easily + * search all tags with a given NAME for a specific value. + */ +struct blkid_struct_tag +{ + struct list_head bit_tags; /* All tags for this device */ + struct list_head bit_names; /* All tags with given NAME */ + char *bit_name; /* NAME of tag (shared) */ + char *bit_val; /* value of tag */ + blkid_dev bit_dev; /* pointer to device */ +}; +typedef struct blkid_struct_tag *blkid_tag; + +/* + * Minimum number of seconds between device probes, even when reading + * from the cache. This is to avoid re-probing all devices which were + * just probed by another program that does not share the cache. + */ +#define BLKID_PROBE_MIN 2 + +/* + * Time in seconds an entry remains verified in the in-memory cache + * before being reverified (in case of long-running processes that + * keep a cache in memory and continue to use it for a long time). + */ +#define BLKID_PROBE_INTERVAL 200 + +/* This describes an entire blkid cache file and probed devices. + * We can traverse all of the found devices via bic_list. + * We can traverse all of the tag types by bic_tags, which hold empty tags + * for each tag type. Those tags can be used as list_heads for iterating + * through all devices with a specific tag type (e.g. LABEL). + */ +struct blkid_struct_cache +{ + struct list_head bic_devs; /* List head of all devices */ + struct list_head bic_tags; /* List head of all tag types */ + time_t bic_time; /* Last probe time */ + time_t bic_ftime; /* Mod time of the cachefile */ + unsigned int bic_flags; /* Status flags of the cache */ + char *bic_filename; /* filename of cache */ +}; + +#define BLKID_BIC_FL_PROBED 0x0002 /* We probed /proc/partition devices */ +#define BLKID_BIC_FL_CHANGED 0x0004 /* Cache has changed from disk */ + +extern char *blkid_strdup(const char *s); +extern char *blkid_strndup(const char *s, const int length); + +#define BLKID_CACHE_FILE "/etc/blkid.tab" + +#define BLKID_ERR_IO 5 +#define BLKID_ERR_PROC 9 +#define BLKID_ERR_MEM 12 +#define BLKID_ERR_CACHE 14 +#define BLKID_ERR_DEV 19 +#define BLKID_ERR_PARAM 22 +#define BLKID_ERR_BIG 27 + +/* + * Priority settings for different types of devices + */ +#define BLKID_PRI_DM 40 +#define BLKID_PRI_EVMS 30 +#define BLKID_PRI_LVM 20 +#define BLKID_PRI_MD 10 + +#if defined(TEST_PROGRAM) && !defined(CONFIG_BLKID_DEBUG) +#define CONFIG_BLKID_DEBUG +#endif + +#define DEBUG_CACHE 0x0001 +#define DEBUG_DUMP 0x0002 +#define DEBUG_DEV 0x0004 +#define DEBUG_DEVNAME 0x0008 +#define DEBUG_DEVNO 0x0010 +#define DEBUG_PROBE 0x0020 +#define DEBUG_READ 0x0040 +#define DEBUG_RESOLVE 0x0080 +#define DEBUG_SAVE 0x0100 +#define DEBUG_TAG 0x0200 +#define DEBUG_INIT 0x8000 +#define DEBUG_ALL 0xFFFF + +#ifdef CONFIG_BLKID_DEBUG +#include +extern int blkid_debug_mask; +#define DBG(m,x) if ((m) & blkid_debug_mask) x; +#else +#define DBG(m,x) +#endif + +#ifdef CONFIG_BLKID_DEBUG +extern void blkid_debug_dump_dev(blkid_dev dev); +extern void blkid_debug_dump_tag(blkid_tag tag); +#endif + +static inline int blkidP_is_disk_device(mode_t mode) +{ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + return S_ISBLK(mode) || S_ISCHR(mode); +#else + return S_ISBLK(mode); +#endif +} + +/* devno.c */ +struct dir_list { + char *name; + struct dir_list *next; +}; +extern void blkid__scan_dir(const char *, dev_t, struct dir_list **, char **); + +/* lseek.c */ +extern blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence); + +/* read.c */ +extern void blkid_read_cache(blkid_cache cache); + +/* save.c */ +extern int blkid_flush_cache(blkid_cache cache); + +/* + * Functions to create and find a specific tag type: tag.c + */ +extern void blkid_free_tag(blkid_tag tag); +extern blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type); +extern int blkid_set_tag(blkid_dev dev, const char *name, + const char *value, const int vlength); + +/* + * Functions to create and find a specific tag type: dev.c + */ +extern blkid_dev blkid_new_dev(void); +extern void blkid_free_dev(blkid_dev dev); + +#ifdef __cplusplus +} +#endif + +#endif /* _BLKID_BLKIDP_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/cache.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/cache.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,209 @@ +/* + * cache.c - allocation/initialization/free routines for cache + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include "config.h" +#if HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#include +#ifdef HAVE_SYS_PRCTL_H +#include +#else +#define PR_GET_DUMPABLE 3 +#endif +#if (!defined(HAVE_PRCTL) && defined(linux)) +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#include "blkidP.h" + +int blkid_debug_mask = 0; + + +static char *safe_getenv(const char *arg) +{ + if ((getuid() != geteuid()) || (getgid() != getegid())) + return NULL; +#if HAVE_PRCTL + if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) + return NULL; +#else +#if (defined(linux) && defined(SYS_prctl)) + if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) + return NULL; +#endif +#endif + +#if defined(HAVE_SECURE_GETENV) + return secure_getenv(arg); +#elif defined(HAVE___SECURE_GETENV) + return __secure_getenv(arg); +#else + return getenv(arg); +#endif +} + +#if 0 /* ifdef CONFIG_BLKID_DEBUG */ +static blkid_debug_dump_cache(int mask, blkid_cache cache) +{ + struct list_head *p; + + if (!cache) { + printf("cache: NULL\n"); + return; + } + + printf("cache: time = %lu\n", cache->bic_time); + printf("cache: flags = 0x%08X\n", cache->bic_flags); + + list_for_each(p, &cache->bic_devs) { + blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); + blkid_debug_dump_dev(dev); + } +} +#endif + +int blkid_get_cache(blkid_cache *ret_cache, const char *filename) +{ + blkid_cache cache; + +#ifdef CONFIG_BLKID_DEBUG + if (!(blkid_debug_mask & DEBUG_INIT)) { + char *dstr = getenv("BLKID_DEBUG"); + + if (dstr) + blkid_debug_mask = strtoul(dstr, 0, 0); + blkid_debug_mask |= DEBUG_INIT; + } +#endif + + DBG(DEBUG_CACHE, printf("creating blkid cache (using %s)\n", + filename ? filename : "default cache")); + + if (!(cache = (blkid_cache) calloc(1, sizeof(struct blkid_struct_cache)))) + return -BLKID_ERR_MEM; + + INIT_LIST_HEAD(&cache->bic_devs); + INIT_LIST_HEAD(&cache->bic_tags); + + if (filename && !strlen(filename)) + filename = 0; + if (!filename) + filename = safe_getenv("BLKID_FILE"); + if (!filename) + filename = BLKID_CACHE_FILE; + cache->bic_filename = blkid_strdup(filename); + + blkid_read_cache(cache); + + *ret_cache = cache; + return 0; +} + +void blkid_put_cache(blkid_cache cache) +{ + if (!cache) + return; + + (void) blkid_flush_cache(cache); + + DBG(DEBUG_CACHE, printf("freeing cache struct\n")); + + /* DBG(DEBUG_CACHE, blkid_debug_dump_cache(cache)); */ + + while (!list_empty(&cache->bic_devs)) { + blkid_dev dev = list_entry(cache->bic_devs.next, + struct blkid_struct_dev, + bid_devs); + blkid_free_dev(dev); + } + + while (!list_empty(&cache->bic_tags)) { + blkid_tag tag = list_entry(cache->bic_tags.next, + struct blkid_struct_tag, + bit_tags); + + while (!list_empty(&tag->bit_names)) { + blkid_tag bad = list_entry(tag->bit_names.next, + struct blkid_struct_tag, + bit_names); + + DBG(DEBUG_CACHE, printf("warning: unfreed tag %s=%s\n", + bad->bit_name, bad->bit_val)); + blkid_free_tag(bad); + } + blkid_free_tag(tag); + } + free(cache->bic_filename); + + free(cache); +} + +void blkid_gc_cache(blkid_cache cache) +{ + struct list_head *p, *pnext; + struct stat st; + + if (!cache) + return; + + list_for_each_safe(p, pnext, &cache->bic_devs) { + blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); + if (stat(dev->bid_name, &st) < 0) { + DBG(DEBUG_CACHE, + printf("freeing %s\n", dev->bid_name)); + blkid_free_dev(dev); + cache->bic_flags |= BLKID_BIC_FL_CHANGED; + } else { + DBG(DEBUG_CACHE, + printf("Device %s exists\n", dev->bid_name)); + } + } +} + + +#ifdef TEST_PROGRAM +int main(int argc, char** argv) +{ + blkid_cache cache = NULL; + int ret; + + blkid_debug_mask = DEBUG_ALL; + if ((argc > 2)) { + fprintf(stderr, "Usage: %s [filename] \n", argv[0]); + exit(1); + } + + if ((ret = blkid_get_cache(&cache, argv[1])) < 0) { + fprintf(stderr, "error %d parsing cache file %s\n", ret, + argv[1] ? argv[1] : BLKID_CACHE_FILE); + exit(1); + } + if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + if ((ret = blkid_probe_all(cache) < 0)) + fprintf(stderr, "error probing devices\n"); + + blkid_put_cache(cache); + + return ret; +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/dev.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/dev.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,254 @@ +/* + * dev.c - allocation/initialization/free routines for dev + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include + +#include "blkidP.h" + +blkid_dev blkid_new_dev(void) +{ + blkid_dev dev; + + if (!(dev = (blkid_dev) calloc(1, sizeof(struct blkid_struct_dev)))) + return NULL; + + INIT_LIST_HEAD(&dev->bid_devs); + INIT_LIST_HEAD(&dev->bid_tags); + + return dev; +} + +void blkid_free_dev(blkid_dev dev) +{ + if (!dev) + return; + + DBG(DEBUG_DEV, + printf(" freeing dev %s (%s)\n", dev->bid_name, dev->bid_type ? + dev->bid_type : "(null)")); + DBG(DEBUG_DEV, blkid_debug_dump_dev(dev)); + + list_del(&dev->bid_devs); + while (!list_empty(&dev->bid_tags)) { + blkid_tag tag = list_entry(dev->bid_tags.next, + struct blkid_struct_tag, + bit_tags); + blkid_free_tag(tag); + } + free(dev->bid_name); + free(dev); +} + +/* + * Given a blkid device, return its name + */ +extern const char *blkid_dev_devname(blkid_dev dev) +{ + return dev->bid_name; +} + +#ifdef CONFIG_BLKID_DEBUG +void blkid_debug_dump_dev(blkid_dev dev) +{ + struct list_head *p; + + if (!dev) { + printf(" dev: NULL\n"); + return; + } + + printf(" dev: name = %s\n", dev->bid_name); + printf(" dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno); + printf(" dev: TIME=\"%ld\"\n", (long)dev->bid_time); + printf(" dev: PRI=\"%d\"\n", dev->bid_pri); + printf(" dev: flags = 0x%08X\n", dev->bid_flags); + + list_for_each(p, &dev->bid_tags) { + blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); + if (tag) + printf(" tag: %s=\"%s\"\n", tag->bit_name, + tag->bit_val); + else + printf(" tag: NULL\n"); + } + printf("\n"); +} +#endif + +/* + * dev iteration routines for the public libblkid interface. + * + * These routines do not expose the list.h implementation, which are a + * contamination of the namespace, and which force us to reveal far, far + * too much of our internal implementation. I'm not convinced I want + * to keep list.h in the long term, anyway. It's fine for kernel + * programming, but performance is not the #1 priority for this + * library, and I really don't like the tradeoff of type-safety for + * performance for this application. [tytso:20030125.2007EST] + */ + +/* + * This series of functions iterate over all devices in a blkid cache + */ +#define DEV_ITERATE_MAGIC 0x01a5284c + +struct blkid_struct_dev_iterate { + int magic; + blkid_cache cache; + char *search_type; + char *search_value; + struct list_head *p; +}; + +extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache) +{ + blkid_dev_iterate iter; + + iter = malloc(sizeof(struct blkid_struct_dev_iterate)); + if (iter) { + iter->magic = DEV_ITERATE_MAGIC; + iter->cache = cache; + iter->p = cache->bic_devs.next; + iter->search_type = 0; + iter->search_value = 0; + } + return (iter); +} + +extern int blkid_dev_set_search(blkid_dev_iterate iter, + char *search_type, char *search_value) +{ + char *new_type, *new_value; + + if (!iter || iter->magic != DEV_ITERATE_MAGIC || !search_type || + !search_value) + return -1; + new_type = malloc(strlen(search_type)+1); + new_value = malloc(strlen(search_value)+1); + if (!new_type || !new_value) { + free(new_type); + free(new_value); + return -1; + } + strcpy(new_type, search_type); + strcpy(new_value, search_value); + free(iter->search_type); + free(iter->search_value); + iter->search_type = new_type; + iter->search_value = new_value; + return 0; +} + +/* + * Return 0 on success, -1 on error + */ +extern int blkid_dev_next(blkid_dev_iterate iter, + blkid_dev *ret_dev) +{ + blkid_dev dev; + + *ret_dev = 0; + if (!iter || iter->magic != DEV_ITERATE_MAGIC) + return -1; + while (iter->p != &iter->cache->bic_devs) { + dev = list_entry(iter->p, struct blkid_struct_dev, bid_devs); + iter->p = iter->p->next; + if (iter->search_type && + !blkid_dev_has_tag(dev, iter->search_type, + iter->search_value)) + continue; + *ret_dev = dev; + return 0; + } + return -1; +} + +extern void blkid_dev_iterate_end(blkid_dev_iterate iter) +{ + if (!iter || iter->magic != DEV_ITERATE_MAGIC) + return; + iter->magic = 0; + free(iter); +} + +#ifdef TEST_PROGRAM +#ifdef HAVE_GETOPT_H +#include +#else +extern char *optarg; +extern int optind; +#endif + +void usage(char *prog) +{ + fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask]\n", prog); + fprintf(stderr, "\tList all devices and exit\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + blkid_dev_iterate iter; + blkid_cache cache = NULL; + blkid_dev dev; + int c, ret; + char *tmp; + char *file = NULL; + char *search_type = NULL; + char *search_value = NULL; + + while ((c = getopt (argc, argv, "m:f:")) != EOF) + switch (c) { + case 'f': + file = optarg; + break; + case 'm': + blkid_debug_mask = strtoul (optarg, &tmp, 0); + if (*tmp) { + fprintf(stderr, "Invalid debug mask: %s\n", + optarg); + exit(1); + } + break; + case '?': + usage(argv[0]); + } + if (argc >= optind+2) { + search_type = argv[optind]; + search_value = argv[optind+1]; + optind += 2; + } + if (argc != optind) + usage(argv[0]); + + if ((ret = blkid_get_cache(&cache, file)) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + + iter = blkid_dev_iterate_begin(cache); + if (search_type) + blkid_dev_set_search(iter, search_type, search_value); + while (blkid_dev_next(iter, &dev) == 0) { + printf("Device: %s\n", blkid_dev_devname(dev)); + } + blkid_dev_iterate_end(iter); + + + blkid_put_cache(cache); + return (0); +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/devname.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/devname.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,561 @@ +/* + * devname.c - get a dev by its device inode name + * + * Copyright (C) Andries Brouwer + * Copyright (C) 1999, 2000, 2001, 2002, 2003 Theodore Ts'o + * Copyright (C) 2001 Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#define _GNU_SOURCE 1 + +#include "config.h" +#include +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#if HAVE_SYS_TYPES_H +#include +#endif +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_SYS_MKDEV_H +#include +#endif +#ifdef HAVE_SYS_SYSMACROS_H +#include +#endif +#include + +#include "blkidP.h" + +/* + * Find a dev struct in the cache by device name, if available. + * + * If there is no entry with the specified device name, and the create + * flag is set, then create an empty device entry. + */ +blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags) +{ + blkid_dev dev = NULL, tmp; + struct list_head *p, *pnext; + + if (!cache || !devname) + return NULL; + + list_for_each(p, &cache->bic_devs) { + tmp = list_entry(p, struct blkid_struct_dev, bid_devs); + if (strcmp(tmp->bid_name, devname)) + continue; + + DBG(DEBUG_DEVNAME, + printf("found devname %s in cache\n", tmp->bid_name)); + dev = tmp; + break; + } + + if (!dev && (flags & BLKID_DEV_CREATE)) { + if (access(devname, F_OK) < 0) + return NULL; + dev = blkid_new_dev(); + if (!dev) + return NULL; + dev->bid_time = INT_MIN; + dev->bid_name = blkid_strdup(devname); + dev->bid_cache = cache; + list_add_tail(&dev->bid_devs, &cache->bic_devs); + cache->bic_flags |= BLKID_BIC_FL_CHANGED; + } + + if (flags & BLKID_DEV_VERIFY) { + dev = blkid_verify(cache, dev); + if (!dev || !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) + return dev; + /* + * If the device is verified, then search the blkid + * cache for any entries that match on the type, uuid, + * and label, and verify them; if a cache entry can + * not be verified, then it's stale and so we remove + * it. + */ + list_for_each_safe(p, pnext, &cache->bic_devs) { + blkid_dev dev2; + dev2 = list_entry(p, struct blkid_struct_dev, bid_devs); + if (dev2->bid_flags & BLKID_BID_FL_VERIFIED) + continue; + if (!dev->bid_type || !dev2->bid_type || + strcmp(dev->bid_type, dev2->bid_type)) + continue; + if (dev->bid_label && dev2->bid_label && + strcmp(dev->bid_label, dev2->bid_label)) + continue; + if (dev->bid_uuid && dev2->bid_uuid && + strcmp(dev->bid_uuid, dev2->bid_uuid)) + continue; + if ((dev->bid_label && !dev2->bid_label) || + (!dev->bid_label && dev2->bid_label) || + (dev->bid_uuid && !dev2->bid_uuid) || + (!dev->bid_uuid && dev2->bid_uuid)) + continue; + dev2 = blkid_verify(cache, dev2); + if (dev2 && !(dev2->bid_flags & BLKID_BID_FL_VERIFIED)) + blkid_free_dev(dev2); + } + } + return dev; +} + +/* Directories where we will try to search for device names */ +static const char *dirlist[] = { "/dev", "/devfs", "/devices", NULL }; + +static int is_dm_leaf(const char *devname) +{ + struct dirent *de, *d_de; + DIR *dir, *d_dir; + char path[256]; + int ret = 1; + + if ((dir = opendir("/sys/block")) == NULL) + return 0; + while ((de = readdir(dir)) != NULL) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") || + !strcmp(de->d_name, devname) || + strncmp(de->d_name, "dm-", 3) || + strlen(de->d_name) > sizeof(path)-32) + continue; + sprintf(path, "/sys/block/%s/slaves", de->d_name); + if ((d_dir = opendir(path)) == NULL) + continue; + while ((d_de = readdir(d_dir)) != NULL) { + if (!strcmp(d_de->d_name, devname)) { + ret = 0; + break; + } + } + closedir(d_dir); + if (!ret) + break; + } + closedir(dir); + return ret; +} + +/* + * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs + * provides the real DM device names in /sys/block//dm/name + */ +static char *get_dm_name(const char *ptname) +{ + FILE *f; + size_t sz; + char path[256], name[256], *res = NULL; + + snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname); + if ((f = fopen(path, "r")) == NULL) + 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); + res = blkid_strdup(path); + } + fclose(f); + return res; +} + +/* + * Probe a single block device to add to the device cache. + */ +static void probe_one(blkid_cache cache, const char *ptname, + dev_t devno, int pri, int only_if_new) +{ + blkid_dev dev = NULL; + struct list_head *p, *pnext; + const char **dir; + char *devname = NULL; + + /* See if we already have this device number in the cache. */ + list_for_each_safe(p, pnext, &cache->bic_devs) { + blkid_dev tmp = list_entry(p, struct blkid_struct_dev, + bid_devs); + if (tmp->bid_devno == devno) { + if (only_if_new && !access(tmp->bid_name, F_OK)) + return; + dev = blkid_verify(cache, tmp); + if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED)) + break; + dev = 0; + } + } + if (dev && dev->bid_devno == devno) + goto set_pri; + + /* Try to translate private device-mapper dm- names + * to standard /dev/mapper/. + */ + if (!strncmp(ptname, "dm-", 3) && isdigit(ptname[3])) { + devname = get_dm_name(ptname); + if (!devname) + blkid__scan_dir("/dev/mapper", devno, 0, &devname); + if (devname) + goto get_dev; + } + + /* + * Take a quick look at /dev/ptname for the device number. We check + * all of the likely device directories. If we don't find it, or if + * the stat information doesn't check out, use blkid_devno_to_devname() + * to find it via an exhaustive search for the device major/minor. + */ + for (dir = dirlist; *dir; dir++) { + struct stat st; + char device[256]; + + sprintf(device, "%s/%s", *dir, ptname); + if ((dev = blkid_get_dev(cache, device, BLKID_DEV_FIND)) && + dev->bid_devno == devno) + goto set_pri; + + if (stat(device, &st) == 0 && + blkidP_is_disk_device(st.st_mode) && + st.st_rdev == devno) { + devname = blkid_strdup(device); + goto get_dev; + } + } + /* Do a short-cut scan of /dev/mapper first */ + if (!devname) + devname = get_dm_name(ptname); + if (!devname) + blkid__scan_dir("/dev/mapper", devno, 0, &devname); + if (!devname) { + devname = blkid_devno_to_devname(devno); + if (!devname) + return; + } +get_dev: + dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL); + free(devname); +set_pri: + if (dev) { + if (pri) + dev->bid_pri = pri; + else if (!strncmp(dev->bid_name, "/dev/mapper/", 11)) { + dev->bid_pri = BLKID_PRI_DM; + if (is_dm_leaf(ptname)) + dev->bid_pri += 5; + } else if (!strncmp(ptname, "md", 2)) + dev->bid_pri = BLKID_PRI_MD; + } + return; +} + +#define PROC_PARTITIONS "/proc/partitions" +#define VG_DIR "/proc/lvm/VGs" + +/* + * This function initializes the UUID cache with devices from the LVM + * proc hierarchy. We currently depend on the names of the LVM + * hierarchy giving us the device structure in /dev. (XXX is this a + * safe thing to do?) + */ +#ifdef VG_DIR +static dev_t lvm_get_devno(const char *lvm_device) +{ + FILE *lvf; + char buf[1024]; + int ma, mi; + dev_t ret = 0; + + DBG(DEBUG_DEVNAME, printf("opening %s\n", lvm_device)); + if ((lvf = fopen(lvm_device, "r")) == NULL) { + DBG(DEBUG_DEVNAME, printf("%s: (%d) %s\n", lvm_device, errno, + strerror(errno))); + return 0; + } + + while (fgets(buf, sizeof(buf), lvf)) { + if (sscanf(buf, "device: %d:%d", &ma, &mi) == 2) { + ret = makedev(ma, mi); + break; + } + } + fclose(lvf); + + return ret; +} + +static void lvm_probe_all(blkid_cache cache, int only_if_new) +{ + DIR *vg_list; + struct dirent *vg_iter; + int vg_len = strlen(VG_DIR); + dev_t dev; + + if ((vg_list = opendir(VG_DIR)) == NULL) + return; + + DBG(DEBUG_DEVNAME, printf("probing LVM devices under %s\n", VG_DIR)); + + while ((vg_iter = readdir(vg_list)) != NULL) { + DIR *lv_list; + char *vdirname; + char *vg_name; + struct dirent *lv_iter; + + vg_name = vg_iter->d_name; + if (!strcmp(vg_name, ".") || !strcmp(vg_name, "..")) + continue; + vdirname = malloc(vg_len + strlen(vg_name) + 8); + if (!vdirname) + goto exit; + sprintf(vdirname, "%s/%s/LVs", VG_DIR, vg_name); + + lv_list = opendir(vdirname); + free(vdirname); + if (lv_list == NULL) + continue; + + while ((lv_iter = readdir(lv_list)) != NULL) { + char *lv_name, *lvm_device; + + lv_name = lv_iter->d_name; + if (!strcmp(lv_name, ".") || !strcmp(lv_name, "..")) + continue; + + lvm_device = malloc(vg_len + strlen(vg_name) + + strlen(lv_name) + 8); + if (!lvm_device) { + closedir(lv_list); + goto exit; + } + sprintf(lvm_device, "%s/%s/LVs/%s", VG_DIR, vg_name, + lv_name); + dev = lvm_get_devno(lvm_device); + sprintf(lvm_device, "%s/%s", vg_name, lv_name); + DBG(DEBUG_DEVNAME, printf("LVM dev %s: devno 0x%04X\n", + lvm_device, + (unsigned int) dev)); + probe_one(cache, lvm_device, dev, BLKID_PRI_LVM, + only_if_new); + free(lvm_device); + } + closedir(lv_list); + } +exit: + closedir(vg_list); +} +#endif + +#define PROC_EVMS_VOLUMES "/proc/evms/volumes" + +static int +evms_probe_all(blkid_cache cache, int only_if_new) +{ + char line[100]; + int ma, mi, sz, num = 0; + FILE *procpt; + char device[110]; + + procpt = fopen(PROC_EVMS_VOLUMES, "r"); + if (!procpt) + return 0; + while (fgets(line, sizeof(line), procpt)) { + if (sscanf (line, " %d %d %d %*s %*s %[^\n ]", + &ma, &mi, &sz, device) != 4) + continue; + + DBG(DEBUG_DEVNAME, printf("Checking partition %s (%d, %d)\n", + device, ma, mi)); + + probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS, + only_if_new); + num++; + } + fclose(procpt); + return num; +} + +/* + * Read the device data for all available block devices in the system. + */ +static int probe_all(blkid_cache cache, int only_if_new) +{ + FILE *proc; + char line[1024]; + char ptname0[129], ptname1[129], *ptname = 0; + char *ptnames[2]; + dev_t devs[2]; + int ma, mi; + unsigned long long sz; + int lens[2] = { 0, 0 }; + int which = 0, last = 0; + struct list_head *p, *pnext; + + ptnames[0] = ptname0; + ptnames[1] = ptname1; + + if (!cache) + return -BLKID_ERR_PARAM; + + if (cache->bic_flags & BLKID_BIC_FL_PROBED && + time(0) - cache->bic_time < BLKID_PROBE_INTERVAL) + return 0; + + blkid_read_cache(cache); + evms_probe_all(cache, only_if_new); +#ifdef VG_DIR + lvm_probe_all(cache, only_if_new); +#endif + + proc = fopen(PROC_PARTITIONS, "r"); + if (!proc) + return -BLKID_ERR_PROC; + + while (fgets(line, sizeof(line), proc)) { + last = which; + which ^= 1; + ptname = ptnames[which]; + + if (sscanf(line, " %d %d %llu %128[^\n ]", + &ma, &mi, &sz, ptname) != 4) + continue; + devs[which] = makedev(ma, mi); + + DBG(DEBUG_DEVNAME, printf("read partition name %s\n", ptname)); + + /* Skip whole disk devs unless they have no partitions. + * If base name of device has changed, also + * check previous dev to see if it didn't have a partn. + * heuristic: partition name ends in a digit, & partition + * names contain whole device name as substring. + * + * Skip extended partitions. + * heuristic: size is 1 + * + * FIXME: skip /dev/{ida,cciss,rd} whole-disk devs + */ + + lens[which] = strlen(ptname); + + /* ends in a digit, clearly a partition, so check */ + if (isdigit(ptname[lens[which] - 1])) { + DBG(DEBUG_DEVNAME, + printf("partition dev %s, devno 0x%04X\n", + ptname, (unsigned int) devs[which])); + + if (sz > 1) + probe_one(cache, ptname, devs[which], 0, + only_if_new); + lens[which] = 0; /* mark as checked */ + } + + /* + * If last was a whole disk and we just found a partition + * on it, remove the whole-disk dev from the cache if + * it exists. + */ + if (lens[last] && !strncmp(ptnames[last], ptname, lens[last])) { + list_for_each_safe(p, pnext, &cache->bic_devs) { + blkid_dev tmp; + + /* find blkid dev for the whole-disk devno */ + tmp = list_entry(p, struct blkid_struct_dev, + bid_devs); + if (tmp->bid_devno == devs[last]) { + DBG(DEBUG_DEVNAME, + printf("freeing %s\n", + tmp->bid_name)); + blkid_free_dev(tmp); + cache->bic_flags |= BLKID_BIC_FL_CHANGED; + break; + } + } + lens[last] = 0; + } + /* + * If last was not checked because it looked like a whole-disk + * dev, and the device's base name has changed, + * check last as well. + */ + if (lens[last] && strncmp(ptnames[last], ptname, lens[last])) { + DBG(DEBUG_DEVNAME, + printf("whole dev %s, devno 0x%04X\n", + ptnames[last], (unsigned int) devs[last])); + probe_one(cache, ptnames[last], devs[last], 0, + only_if_new); + lens[last] = 0; + } + } + + /* Handle the last device if it wasn't partitioned */ + if (lens[which]) + probe_one(cache, ptname, devs[which], 0, only_if_new); + + fclose(proc); + blkid_flush_cache(cache); + return 0; +} + +int blkid_probe_all(blkid_cache cache) +{ + int ret; + + DBG(DEBUG_PROBE, printf("Begin blkid_probe_all()\n")); + ret = probe_all(cache, 0); + cache->bic_time = time(0); + cache->bic_flags |= BLKID_BIC_FL_PROBED; + DBG(DEBUG_PROBE, printf("End blkid_probe_all()\n")); + return ret; +} + +int blkid_probe_all_new(blkid_cache cache) +{ + int ret; + + DBG(DEBUG_PROBE, printf("Begin blkid_probe_all_new()\n")); + ret = probe_all(cache, 1); + DBG(DEBUG_PROBE, printf("End blkid_probe_all_new()\n")); + return ret; +} + + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + blkid_cache cache = NULL; + int ret; + + blkid_debug_mask = DEBUG_ALL; + if (argc != 1) { + fprintf(stderr, "Usage: %s\n" + "Probe all devices and exit\n", argv[0]); + exit(1); + } + if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + if (blkid_probe_all(cache) < 0) + printf("%s: error probing devices\n", argv[0]); + + blkid_put_cache(cache); + return (0); +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/devno.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/devno.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,232 @@ +/* + * devno.c - find a particular device by its device number (major/minor) + * + * Copyright (C) 2000, 2001, 2003 Theodore Ts'o + * Copyright (C) 2001 Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#include +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_SYS_MKDEV_H +#include +#endif +#ifdef HAVE_SYS_SYSMACROS_H +#include +#endif + +#include "blkidP.h" + +char *blkid_strndup(const char *s, int length) +{ + char *ret; + + if (!s) + return NULL; + + if (!length) + length = strlen(s); + + ret = malloc(length + 1); + if (ret) { + strncpy(ret, s, length); + ret[length] = '\0'; + } + return ret; +} + +char *blkid_strdup(const char *s) +{ + return blkid_strndup(s, 0); +} + +/* + * This function adds an entry to the directory list + */ +static void add_to_dirlist(const char *name, struct dir_list **list) +{ + struct dir_list *dp; + + dp = malloc(sizeof(struct dir_list)); + if (!dp) + return; + dp->name = blkid_strdup(name); + if (!dp->name) { + free(dp); + return; + } + dp->next = *list; + *list = dp; +} + +/* + * This function frees a directory list + */ +static void free_dirlist(struct dir_list **list) +{ + struct dir_list *dp, *next; + + for (dp = *list; dp; dp = next) { + next = dp->next; + free(dp->name); + free(dp); + } + *list = NULL; +} + +void blkid__scan_dir(const char *dirname, dev_t devno, struct dir_list **list, + char **devname) +{ + DIR *dir; + struct dirent *dp; + char path[1024]; + int dirlen; + struct stat st; + + if ((dir = opendir(dirname)) == NULL) + return; + dirlen = strlen(dirname) + 2; + while ((dp = readdir(dir)) != 0) { + if (dirlen + strlen(dp->d_name) >= sizeof(path)) + continue; + + if (dp->d_name[0] == '.' && + ((dp->d_name[1] == 0) || + ((dp->d_name[1] == '.') && (dp->d_name[2] == 0)))) + continue; + + sprintf(path, "%s/%s", dirname, dp->d_name); + if (stat(path, &st) < 0) + continue; + + if (blkidP_is_disk_device(st.st_mode) && st.st_rdev == devno) { + *devname = blkid_strdup(path); + DBG(DEBUG_DEVNO, + printf("found 0x%llx at %s (%p)\n", (long long)devno, + path, *devname)); + break; + } + if (list && S_ISDIR(st.st_mode) && !lstat(path, &st) && + S_ISDIR(st.st_mode)) + add_to_dirlist(path, list); + } + closedir(dir); + return; +} + +/* Directories where we will try to search for device numbers */ +static const char *devdirs[] = { "/devices", "/devfs", "/dev", NULL }; + +/* + * This function finds the pathname to a block device with a given + * device number. It returns a pointer to allocated memory to the + * pathname on success, and NULL on failure. + */ +char *blkid_devno_to_devname(dev_t devno) +{ + struct dir_list *list = NULL, *new_list = NULL; + char *devname = NULL; + const char **dir; + + /* + * Add the starting directories to search in reverse order of + * importance, since we are using a stack... + */ + for (dir = devdirs; *dir; dir++) + add_to_dirlist(*dir, &list); + + while (list) { + struct dir_list *current = list; + + list = list->next; + DBG(DEBUG_DEVNO, printf("directory %s\n", current->name)); + blkid__scan_dir(current->name, devno, &new_list, &devname); + free(current->name); + free(current); + if (devname) + break; + /* + * If we're done checking at this level, descend to + * the next level of subdirectories. (breadth-first) + */ + if (list == NULL) { + list = new_list; + new_list = NULL; + } + } + free_dirlist(&list); + free_dirlist(&new_list); + + if (!devname) { + DBG(DEBUG_DEVNO, + printf("blkid: couldn't find devno 0x%04lx\n", + (unsigned long) devno)); + } else { + DBG(DEBUG_DEVNO, + printf("found devno 0x%04llx as %s\n", (long long)devno, devname)); + } + + + return devname; +} + +#ifdef TEST_PROGRAM +int main(int argc, char** argv) +{ + char *devname, *tmp; + int major, minor; + dev_t devno; + const char *errmsg = "Couldn't parse %s: %s\n"; + + blkid_debug_mask = DEBUG_ALL; + if ((argc != 2) && (argc != 3)) { + fprintf(stderr, "Usage:\t%s device_number\n\t%s major minor\n" + "Resolve a device number to a device name\n", + argv[0], argv[0]); + exit(1); + } + if (argc == 2) { + devno = strtoul(argv[1], &tmp, 0); + if (*tmp) { + fprintf(stderr, errmsg, "device number", argv[1]); + exit(1); + } + } else { + major = strtoul(argv[1], &tmp, 0); + if (*tmp) { + fprintf(stderr, errmsg, "major number", argv[1]); + exit(1); + } + minor = strtoul(argv[2], &tmp, 0); + if (*tmp) { + fprintf(stderr, errmsg, "minor number", argv[2]); + exit(1); + } + devno = makedev(major, minor); + } + printf("Looking for device 0x%04llx\n", (long long)devno); + devname = blkid_devno_to_devname(devno); + free(devname); + return 0; +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/getsize.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/getsize.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,217 @@ +/* + * getsize.c --- get the size of a partition. + * + * Copyright (C) 1995, 1995 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#include "config.h" +#include "blkidP.h" + +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_LINUX_FD_H +#include +#endif +#ifdef HAVE_SYS_DISKLABEL_H +#include +#endif +#ifdef HAVE_SYS_DISK_H +#include +#endif +#ifdef __linux__ +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif + + +#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE) +#define BLKGETSIZE _IO(0x12,96) /* return device size */ +#endif + +#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64) +#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */ +#endif + +#ifdef APPLE_DARWIN +#define BLKGETSIZE DKIOCGETBLOCKCOUNT32 +#endif /* APPLE_DARWIN */ + +static int valid_offset(int fd, blkid_loff_t offset) +{ + char ch; + + if (blkid_llseek(fd, offset, 0) < 0) + return 0; + if (read(fd, &ch, 1) < 1) + return 0; + return 1; +} + +/* + * Returns the number of bytes in a partition + */ +blkid_loff_t blkid_get_dev_size(int fd) +{ + unsigned long long size64; + blkid_loff_t high, low; + +#if defined DKIOCGETBLOCKCOUNT && defined DKIOCGETBLOCKSIZE /* For Apple Darwin */ + unsigned int size; + + if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0 && + ioctl(fd, DKIOCGETBLOCKSIZE, &size) >= 0) { + if (sizeof(blkid_loff_t) < sizeof(unsigned long long) && + (size64 * size) > 0xFFFFFFFF) + return 0; /* EFBIG */ + return (blkid_loff_t)size64 * size; + } +#endif + +#ifdef BLKGETSIZE64 + { + int valid_blkgetsize64 = 1; +#ifdef __linux__ + struct utsname ut; + + if ((uname(&ut) == 0) && + ((ut.release[0] == '2') && (ut.release[1] == '.') && + (ut.release[2] < '6') && (ut.release[3] == '.'))) + valid_blkgetsize64 = 0; +#endif + if (valid_blkgetsize64 && + ioctl(fd, BLKGETSIZE64, &size64) >= 0) { + if (sizeof(blkid_loff_t) < sizeof(unsigned long long) && + (size64 > 0xFFFFFFFF)) + return 0; /* EFBIG */ + return size64; + } + } +#endif /* BLKGETSIZE64 */ + +#ifdef BLKGETSIZE + { + unsigned long size; + + if (ioctl(fd, BLKGETSIZE, &size) >= 0) + return (blkid_loff_t)size << 9; + } +#endif + +/* tested on FreeBSD 6.1-RELEASE i386 */ +#ifdef DIOCGMEDIASIZE + if (ioctl(fd, DIOCGMEDIASIZE, &size64) >= 0) + return (off_t)size64; +#endif /* DIOCGMEDIASIZE */ + +#ifdef FDGETPRM + { + struct floppy_struct this_floppy; + + if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) + return (blkid_loff_t)this_floppy.size << 9; + } +#endif +#if defined(HAVE_SYS_DISKLABEL_H) && defined(DIOCGDINFO) + { + int part = -1; + struct disklabel lab; + struct partition *pp; + char ch; + struct stat st; + + /* + * This code works for FreeBSD 4.11 i386, except for the full + * device (such as /dev/ad0). It doesn't work properly for + * newer FreeBSD though. FreeBSD >= 5.0 should be covered by + * the DIOCGMEDIASIZE above however. + * + * Note that FreeBSD >= 4.0 has disk devices as unbuffered (raw, + * character) devices, so we need to check for S_ISCHR, too. + */ + if (fstat(fd, &st) >= 0 && + blkidP_is_disk_device(st.st_mode)) + part = st.st_rdev & 7; + + if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) { + pp = &lab.d_partitions[part]; + if (pp->p_size) + return pp->p_size << 9; + } + } +#endif /* defined(HAVE_SYS_DISKLABEL_H) && defined(DIOCGDINFO) */ + { +#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) + struct stat64 st; + if (fstat64(fd, &st) == 0) +#else + struct stat st; + if (fstat(fd, &st) == 0) +#endif + if (S_ISREG(st.st_mode)) + return st.st_size; + } + + /* + * OK, we couldn't figure it out by using a specialized ioctl, + * which is generally the best way. So do binary search to + * find the size of the partition. + */ + low = 0; + for (high = 1024; valid_offset(fd, high); high *= 2) + low = high; + while (low < high - 1) { + const blkid_loff_t mid = (low + high) / 2; + + if (valid_offset(fd, mid)) + low = mid; + else + high = mid; + } + return low + 1; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + long long bytes; + int fd; + + if (argc < 2) { + fprintf(stderr, "Usage: %s device\n" + "Determine the size of a device\n", argv[0]); + return 1; + } + + if ((fd = open(argv[1], O_RDONLY)) < 0) + perror(argv[0]); + + bytes = blkid_get_dev_size(fd); + printf("Device %s has %lld 1k blocks.\n", argv[1], + (unsigned long long)bytes >> 10); + + return 0; +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/llseek.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/llseek.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,147 @@ +/* + * llseek.c -- stub calling the llseek system call + * + * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#include "config.h" +#if HAVE_SYS_TYPES_H +#include +#endif + +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#ifdef __MSDOS__ +#include +#endif + +#include "blkidP.h" + +#ifdef __linux__ + +#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) + +#define my_llseek lseek64 + +#elif defined(HAVE_LLSEEK) +#include + +#ifndef HAVE_LLSEEK_PROTOTYPE +extern long long llseek(int fd, long long offset, int origin); +#endif + +#define my_llseek llseek + +#else /* ! HAVE_LLSEEK */ + +#if SIZEOF_LONG == SIZEOF_LONG_LONG + +#define llseek lseek + +#else /* SIZEOF_LONG != SIZEOF_LONG_LONG */ + +#include + +#ifndef __NR__llseek +#define __NR__llseek 140 +#endif + +#ifndef __i386__ +static int _llseek(unsigned int, unsigned long, unsigned long, + blkid_loff_t *, unsigned int); + +static _syscall5(int, _llseek, unsigned int, fd, unsigned long, offset_high, + unsigned long, offset_low, blkid_loff_t *, result, + unsigned int, origin) +#endif + +static blkid_loff_t my_llseek(int fd, blkid_loff_t offset, int origin) +{ + blkid_loff_t result; + int retval; + +#ifndef __i386__ + retval = _llseek(fd, ((unsigned long long) offset) >> 32, + ((unsigned long long)offset) & 0xffffffff, + &result, origin); +#else + retval = syscall(__NR__llseek, fd, ((unsigned long long) offset) >> 32, + ((unsigned long long)offset) & 0xffffffff, + &result, origin); +#endif + return (retval == -1 ? (blkid_loff_t) retval : result); +} + +#endif /* __alpha__ || __ia64__ */ + +#endif /* HAVE_LLSEEK */ + +blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence) +{ + blkid_loff_t result; + static int do_compat = 0; + + if ((sizeof(off_t) >= sizeof(blkid_loff_t)) || + (offset < ((blkid_loff_t) 1 << ((sizeof(off_t)*8) -1)))) + return lseek(fd, (off_t) offset, whence); + + if (do_compat) { + errno = EOVERFLOW; + return -1; + } + + result = my_llseek(fd, offset, whence); + if (result == -1 && errno == ENOSYS) { + /* + * Just in case this code runs on top of an old kernel + * which does not support the llseek system call + */ + do_compat++; + errno = EOVERFLOW; + } + return result; +} + +#else /* !linux */ + +#ifndef EOVERFLOW +#ifdef EXT2_ET_INVALID_ARGUMENT +#define EOVERFLOW EXT2_ET_INVALID_ARGUMENT +#else +#define EOVERFLOW 112 +#endif +#endif + +blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int origin) +{ +#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) + return lseek64 (fd, offset, origin); +#else + if ((sizeof(off_t) < sizeof(blkid_loff_t)) && + (offset >= ((blkid_loff_t) 1 << ((sizeof(off_t)*8) - 1)))) { + errno = EOVERFLOW; + return -1; + } + return lseek(fd, (off_t) offset, origin); +#endif +} + +#endif /* linux */ + + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/probe.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/probe.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,1840 @@ +/* + * probe.c - identify a block device by its contents, and return a dev + * struct with the details + * + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_MKDEV_H +#include +#endif +#ifdef __linux__ +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#include "blkidP.h" +#include "uuid/uuid.h" +#include "probe.h" + +static int figure_label_len(const unsigned char *label, int len) +{ + const unsigned char *end = label + len - 1; + + while (end >= label && (*end == ' ' || *end == 0)) + --end; + if (end >= label) + return end - label + 1; + return 0; +} + +static unsigned char *get_buffer(struct blkid_probe *pr, + blkid_loff_t off, size_t len) +{ + ssize_t ret_read; + unsigned char *newbuf; + + if (off + len <= SB_BUFFER_SIZE) { + if (!pr->sbbuf) { + pr->sbbuf = malloc(SB_BUFFER_SIZE); + if (!pr->sbbuf) + return NULL; + if (lseek(pr->fd, 0, SEEK_SET) < 0) + return NULL; + ret_read = read(pr->fd, pr->sbbuf, SB_BUFFER_SIZE); + if (ret_read < 0) + ret_read = 0; + pr->sb_valid = ret_read; + } + if (off+len > pr->sb_valid) + return NULL; + return pr->sbbuf + off; + } else { + if (len > pr->buf_max) { + newbuf = realloc(pr->buf, len); + if (newbuf == NULL) + return NULL; + pr->buf = newbuf; + pr->buf_max = len; + } + if (blkid_llseek(pr->fd, off, SEEK_SET) < 0) + return NULL; + ret_read = read(pr->fd, pr->buf, len); + if (ret_read != (ssize_t) len) + return NULL; + return pr->buf; + } +} + + +/* + * This is a special case code to check for an MDRAID device. We do + * this special since it requires checking for a superblock at the end + * of the device. + */ +static int check_mdraid(int fd, unsigned char *ret_uuid) +{ + struct mdp_superblock_s *md; + blkid_loff_t offset; + char buf[4096]; + + if (fd < 0) + return -BLKID_ERR_PARAM; + + offset = (blkid_get_dev_size(fd) & ~((blkid_loff_t)65535)) - 65536; + + if (blkid_llseek(fd, offset, 0) < 0 || + read(fd, buf, 4096) != 4096) + return -BLKID_ERR_IO; + /* Check for magic number */ + if (memcmp("\251+N\374", buf, 4) && memcmp("\374N+\251", buf, 4)) + return -BLKID_ERR_PARAM; + + if (!ret_uuid) + return 0; + *ret_uuid = 0; + + /* The MD UUID is not contiguous in the superblock, make it so */ + md = (struct mdp_superblock_s *)buf; + if (md->set_uuid0 || md->set_uuid1 || md->set_uuid2 || md->set_uuid3) { + memcpy(ret_uuid, &md->set_uuid0, 4); + memcpy(ret_uuid + 4, &md->set_uuid1, 12); + } + return 0; +} + +static void set_uuid(blkid_dev dev, uuid_t uuid, const char *tag) +{ + char str[37]; + + if (!uuid_is_null(uuid)) { + uuid_unparse(uuid, str); + blkid_set_tag(dev, tag ? tag : "UUID", str, sizeof(str)); + } +} + +static void get_ext2_info(blkid_dev dev, struct blkid_magic *id, + unsigned char *buf) +{ + struct ext2_super_block *es = (struct ext2_super_block *) buf; + const char *label = 0; + + DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n", + blkid_le32(es->s_feature_compat), + blkid_le32(es->s_feature_incompat), + blkid_le32(es->s_feature_ro_compat))); + + if (strlen(es->s_volume_name)) + label = es->s_volume_name; + blkid_set_tag(dev, "LABEL", label, sizeof(es->s_volume_name)); + + set_uuid(dev, es->s_uuid, 0); + + if ((es->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && + !uuid_is_null(es->s_journal_uuid)) + set_uuid(dev, es->s_journal_uuid, "EXT_JOURNAL"); + + if (strcmp(id->bim_type, "ext2") && + ((blkid_le32(es->s_feature_incompat) & + EXT2_FEATURE_INCOMPAT_UNSUPPORTED) == 0)) + blkid_set_tag(dev, "SEC_TYPE", "ext2", sizeof("ext2")); +} + +/* + * Check to see if a filesystem is in /proc/filesystems. + * Returns 1 if found, 0 if not + */ +static int fs_proc_check(const char *fs_name) +{ + FILE *f; + char buf[80], *cp, *t; + + f = fopen("/proc/filesystems", "r"); + if (!f) + return (0); + while (!feof(f)) { + if (!fgets(buf, sizeof(buf), f)) + break; + cp = buf; + if (!isspace(*cp)) { + while (*cp && !isspace(*cp)) + cp++; + } + while (*cp && isspace(*cp)) + cp++; + if ((t = strchr(cp, '\n')) != NULL) + *t = 0; + if ((t = strchr(cp, '\t')) != NULL) + *t = 0; + if ((t = strchr(cp, ' ')) != NULL) + *t = 0; + if (!strcmp(fs_name, cp)) { + fclose(f); + return (1); + } + } + fclose(f); + return (0); +} + +/* + * Check to see if a filesystem is available as a module + * Returns 1 if found, 0 if not + */ +static int check_for_modules(const char *fs_name) +{ +#ifdef __linux__ + struct utsname uts; + FILE *f; + char buf[1024], *cp; + int namesz; + + if (uname(&uts)) + return (0); + snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release); + + f = fopen(buf, "r"); + if (!f) + return (0); + + namesz = strlen(fs_name); + + while (!feof(f)) { + if (!fgets(buf, sizeof(buf), f)) + break; + if ((cp = strchr(buf, ':')) != NULL) + *cp = 0; + else + continue; + if ((cp = strrchr(buf, '/')) != NULL) + cp++; + else + cp = buf; + if (!strncmp(cp, fs_name, namesz) && + (!strcmp(cp + namesz, ".ko") || + !strcmp(cp + namesz, ".ko.gz"))) { + fclose(f); + return (1); + } + } + fclose(f); +#endif + return (0); +} + +static int linux_version_code(void) +{ +#ifdef __linux__ + struct utsname ut; + static int version_code = -1; + int major, minor, rev; + char *endptr; + const char *cp; + + if (version_code > 0) + return version_code; + + if (uname(&ut)) + return 0; + cp = ut.release; + + major = strtol(cp, &endptr, 10); + if (cp == endptr || *endptr != '.') + return 0; + cp = endptr + 1; + minor = strtol(cp, &endptr, 10); + if (cp == endptr || *endptr != '.') + return 0; + cp = endptr + 1; + rev = strtol(cp, &endptr, 10); + if (cp == endptr) + return 0; + version_code = (((major * 256) + minor) * 256) + rev; + return version_code; +#else + return 0; +#endif +} + +#define EXT4_SUPPORTS_EXT2 (2 * 65536 + 6*256 + 29) + +static int system_supports_ext2(void) +{ + static time_t last_check = 0; + static int ret = -1; + time_t now = time(0); + + if (ret != -1 || (now - last_check) < 5) + return ret; + last_check = now; + ret = (fs_proc_check("ext2") || check_for_modules("ext2")); + return ret; +} + +static int system_supports_ext4(void) +{ + static time_t last_check = 0; + static int ret = -1; + time_t now = time(0); + + if (ret != -1 || (now - last_check) < 5) + return ret; + last_check = now; + ret = (fs_proc_check("ext4") || check_for_modules("ext4")); + return ret; +} + +static int system_supports_ext4dev(void) +{ + static time_t last_check = 0; + static int ret = -1; + time_t now = time(0); + + if (ret != -1 || (now - last_check) < 5) + return ret; + last_check = now; + ret = (fs_proc_check("ext4dev") || check_for_modules("ext4dev")); + return ret; +} + +static int probe_ext4dev(struct blkid_probe *probe, + struct blkid_magic *id, + unsigned char *buf) +{ + struct ext2_super_block *es; + es = (struct ext2_super_block *)buf; + + /* Distinguish from jbd */ + if (blkid_le32(es->s_feature_incompat) & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) + return -BLKID_ERR_PARAM; + + /* + * If the filesystem does not have a journal and ext2 and ext4 + * is not present, then force this to be detected as an + * ext4dev filesystem. + */ + if (!(blkid_le32(es->s_feature_compat) & + EXT3_FEATURE_COMPAT_HAS_JOURNAL) && + !system_supports_ext2() && !system_supports_ext4() && + system_supports_ext4dev() && + linux_version_code() >= EXT4_SUPPORTS_EXT2) + goto force_ext4dev; + + /* + * If the filesystem is marked as OK for use by in-development + * filesystem code, but ext4dev is not supported, and ext4 is, + * then don't call ourselves ext4dev, since we should be + * detected as ext4 in that case. + * + * If the filesystem is marked as in use by production + * filesystem, then it can only be used by ext4 and NOT by + * ext4dev, so always disclaim we are ext4dev in that case. + */ + if (blkid_le32(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) { + if (!system_supports_ext4dev() && system_supports_ext4()) + return -BLKID_ERR_PARAM; + } else + return -BLKID_ERR_PARAM; + +force_ext4dev: + get_ext2_info(probe->dev, id, buf); + return 0; +} + +static int probe_ext4(struct blkid_probe *probe, struct blkid_magic *id, + unsigned char *buf) +{ + struct ext2_super_block *es; + es = (struct ext2_super_block *)buf; + + /* Distinguish from jbd */ + if (blkid_le32(es->s_feature_incompat) & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) + return -BLKID_ERR_PARAM; + + /* + * If the filesystem does not have a journal and ext2 is not + * present, then force this to be detected as an ext2 + * filesystem. + */ + if (!(blkid_le32(es->s_feature_compat) & + EXT3_FEATURE_COMPAT_HAS_JOURNAL) && + !system_supports_ext2() && system_supports_ext4() && + linux_version_code() >= EXT4_SUPPORTS_EXT2) + goto force_ext4; + + /* Ext4 has at least one feature which ext3 doesn't understand */ + if (!(blkid_le32(es->s_feature_ro_compat) & + EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) && + !(blkid_le32(es->s_feature_incompat) & + EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) + return -BLKID_ERR_PARAM; + +force_ext4: + /* + * If the filesystem is a OK for use by in-development + * filesystem code, and ext4dev is supported or ext4 is not + * supported, then don't call ourselves ext4, so we can redo + * the detection and mark the filesystem as ext4dev. + * + * If the filesystem is marked as in use by production + * filesystem, then it can only be used by ext4 and NOT by + * ext4dev. + */ + if (blkid_le32(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) { + if (system_supports_ext4dev() || !system_supports_ext4()) + return -BLKID_ERR_PARAM; + } + get_ext2_info(probe->dev, id, buf); + return 0; +} + +static int probe_ext3(struct blkid_probe *probe, struct blkid_magic *id, + unsigned char *buf) +{ + struct ext2_super_block *es; + es = (struct ext2_super_block *)buf; + + /* ext3 requires journal */ + if (!(blkid_le32(es->s_feature_compat) & + EXT3_FEATURE_COMPAT_HAS_JOURNAL)) + return -BLKID_ERR_PARAM; + + /* Any features which ext3 doesn't understand */ + if ((blkid_le32(es->s_feature_ro_compat) & + EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) || + (blkid_le32(es->s_feature_incompat) & + EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) + return -BLKID_ERR_PARAM; + + get_ext2_info(probe->dev, id, buf); + return 0; +} + +static int probe_ext2(struct blkid_probe *probe, struct blkid_magic *id, + unsigned char *buf) +{ + struct ext2_super_block *es; + + es = (struct ext2_super_block *)buf; + + /* Distinguish between ext3 and ext2 */ + if ((blkid_le32(es->s_feature_compat) & + EXT3_FEATURE_COMPAT_HAS_JOURNAL)) + return -BLKID_ERR_PARAM; + + /* Any features which ext2 doesn't understand */ + if ((blkid_le32(es->s_feature_ro_compat) & + EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) || + (blkid_le32(es->s_feature_incompat) & + EXT2_FEATURE_INCOMPAT_UNSUPPORTED)) + return -BLKID_ERR_PARAM; + + /* + * If ext2 is not present, but ext4 or ext4dev are, then + * disclaim we are ext2 + */ + if (!system_supports_ext2() && + (system_supports_ext4() || system_supports_ext4dev()) && + linux_version_code() >= EXT4_SUPPORTS_EXT2) + return -BLKID_ERR_PARAM; + + get_ext2_info(probe->dev, id, buf); + return 0; +} + +static int probe_jbd(struct blkid_probe *probe, struct blkid_magic *id, + unsigned char *buf) +{ + struct ext2_super_block *es = (struct ext2_super_block *) buf; + + if (!(blkid_le32(es->s_feature_incompat) & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) + return -BLKID_ERR_PARAM; + + get_ext2_info(probe->dev, id, buf); + + return 0; +} + +#define FAT_ATTR_VOLUME_ID 0x08 +#define FAT_ATTR_DIR 0x10 +#define FAT_ATTR_LONG_NAME 0x0f +#define FAT_ATTR_MASK 0x3f +#define FAT_ENTRY_FREE 0xe5 + +static const char *no_name = "NO NAME "; + +static unsigned char *search_fat_label(struct vfat_dir_entry *dir, int count) +{ + int i; + + for (i = 0; i < count; i++) { + if (dir[i].name[0] == 0x00) + break; + + if ((dir[i].name[0] == FAT_ENTRY_FREE) || + (dir[i].cluster_high != 0 || dir[i].cluster_low != 0) || + ((dir[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)) + continue; + + if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == + FAT_ATTR_VOLUME_ID) { + return dir[i].name; + } + } + return 0; +} + +/* FAT label extraction from the root directory taken from Kay + * Sievers's volume_id library */ +static int probe_fat(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct vfat_super_block *vs = (struct vfat_super_block *) buf; + struct msdos_super_block *ms = (struct msdos_super_block *) buf; + struct vfat_dir_entry *dir; + char serno[10]; + const unsigned char *label = 0, *vol_label = 0, *tmp; + unsigned char *vol_serno; + int label_len = 0, maxloop = 100; + __u16 sector_size, dir_entries, reserved; + __u32 sect_count, fat_size, dir_size, cluster_count, fat_length; + __u32 buf_size, start_data_sect, next, root_start, root_dir_entries; + + /* sector size check */ + tmp = (unsigned char *)&ms->ms_sector_size; + sector_size = tmp[0] + (tmp[1] << 8); + if (sector_size != 0x200 && sector_size != 0x400 && + sector_size != 0x800 && sector_size != 0x1000) + return 1; + + tmp = (unsigned char *)&ms->ms_dir_entries; + dir_entries = tmp[0] + (tmp[1] << 8); + reserved = blkid_le16(ms->ms_reserved); + tmp = (unsigned char *)&ms->ms_sectors; + sect_count = tmp[0] + (tmp[1] << 8); + if (sect_count == 0) + sect_count = blkid_le32(ms->ms_total_sect); + + fat_length = blkid_le16(ms->ms_fat_length); + if (fat_length == 0) + fat_length = blkid_le32(vs->vs_fat32_length); + + fat_size = fat_length * ms->ms_fats; + dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) + + (sector_size-1)) / sector_size; + + cluster_count = sect_count - (reserved + fat_size + dir_size); + if (ms->ms_cluster_size == 0) + return 1; + cluster_count /= ms->ms_cluster_size; + + if (cluster_count > FAT32_MAX) + return 1; + + if (ms->ms_fat_length) { + /* the label may be an attribute in the root directory */ + root_start = (reserved + fat_size) * sector_size; + root_dir_entries = vs->vs_dir_entries[0] + + (vs->vs_dir_entries[1] << 8); + + buf_size = root_dir_entries * sizeof(struct vfat_dir_entry); + dir = (struct vfat_dir_entry *) get_buffer(probe, root_start, + buf_size); + if (dir) + vol_label = search_fat_label(dir, root_dir_entries); + + if (!vol_label || !memcmp(vol_label, no_name, 11)) + vol_label = ms->ms_label; + vol_serno = ms->ms_serno; + + blkid_set_tag(probe->dev, "SEC_TYPE", "msdos", + sizeof("msdos")); + } else { + /* Search the FAT32 root dir for the label attribute */ + buf_size = vs->vs_cluster_size * sector_size; + start_data_sect = reserved + fat_size; + + next = blkid_le32(vs->vs_root_cluster); + while (next && --maxloop) { + __u32 next_sect_off; + __u64 next_off, fat_entry_off; + int count; + + next_sect_off = (next - 2) * vs->vs_cluster_size; + next_off = (__u64) (start_data_sect + next_sect_off) * + sector_size; + + dir = (struct vfat_dir_entry *) + get_buffer(probe, next_off, buf_size); + if (dir == NULL) + break; + + count = buf_size / sizeof(struct vfat_dir_entry); + + vol_label = search_fat_label(dir, count); + if (vol_label) + break; + + /* get FAT entry */ + fat_entry_off = + ((unsigned int) reserved * + (unsigned int) sector_size) + + (next * sizeof(__u32)); + buf = get_buffer(probe, fat_entry_off, buf_size); + if (buf == NULL) + break; + + /* set next cluster */ + next = blkid_le32(*((__u32 *) buf) & 0x0fffffff); + } + + if (!vol_label || !memcmp(vol_label, no_name, 11)) + vol_label = vs->vs_label; + vol_serno = vs->vs_serno; + } + + if (vol_label && memcmp(vol_label, no_name, 11)) { + if ((label_len = figure_label_len(vol_label, 11))) + label = vol_label; + } + + /* We can't just print them as %04X, because they are unaligned */ + sprintf(serno, "%02X%02X-%02X%02X", vol_serno[3], vol_serno[2], + vol_serno[1], vol_serno[0]); + + blkid_set_tag(probe->dev, "LABEL", (const char *) label, label_len); + blkid_set_tag(probe->dev, "UUID", serno, sizeof(serno)-1); + + return 0; +} + +/* + * The FAT filesystem could be without a magic string in superblock + * (e.g. old floppies). This heuristic for FAT detection is inspired + * by http://vrfy.org/projects/volume_id/ and Linux kernel. + * [7-Jul-2005, Karel Zak ] + */ +static int probe_fat_nomagic(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct msdos_super_block *ms; + + ms = (struct msdos_super_block *)buf; + + /* heads check */ + if (ms->ms_heads == 0) + return 1; + + /* cluster size check*/ + if (ms->ms_cluster_size == 0 || + (ms->ms_cluster_size & (ms->ms_cluster_size-1))) + return 1; + + /* media check */ + if (ms->ms_media < 0xf8 && ms->ms_media != 0xf0) + return 1; + + /* fat counts(Linux kernel expects at least 1 FAT table) */ + if (!ms->ms_fats) + return 1; + + /* + * OS/2 and apparently DFSee will place a FAT12/16-like + * pseudo-superblock in the first 512 bytes of non-FAT + * filesystems --- at least JFS and HPFS, and possibly others. + * So we explicitly check for those filesystems at the + * FAT12/16 filesystem magic field identifier, and if they are + * present, we rule this out as a FAT filesystem, despite the + * FAT-like pseudo-header. + */ + if ((memcmp(ms->ms_magic, "JFS ", 8) == 0) || + (memcmp(ms->ms_magic, "HPFS ", 8) == 0)) + return 1; + + return probe_fat(probe, id, buf); +} + +static int probe_ntfs(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct ntfs_super_block *ns; + struct master_file_table_record *mft; + struct file_attribute *attr; + char uuid_str[17], label_str[129], *cp; + int bytes_per_sector, sectors_per_cluster; + int mft_record_size, attr_off, attr_len; + unsigned int i, attr_type, val_len; + int val_off; + __u64 nr_clusters; + blkid_loff_t off; + unsigned char *buf_mft, *val; + + ns = (struct ntfs_super_block *) buf; + + bytes_per_sector = ns->bios_parameter_block[0] + + (ns->bios_parameter_block[1] << 8); + sectors_per_cluster = ns->bios_parameter_block[2]; + + if ((bytes_per_sector < 512) || (sectors_per_cluster == 0)) + return 1; + + if (ns->cluster_per_mft_record < 0) + mft_record_size = 1 << (0-ns->cluster_per_mft_record); + else + mft_record_size = ns->cluster_per_mft_record * + sectors_per_cluster * bytes_per_sector; + nr_clusters = blkid_le64(ns->number_of_sectors) / sectors_per_cluster; + + if ((blkid_le64(ns->mft_cluster_location) > nr_clusters) || + (blkid_le64(ns->mft_mirror_cluster_location) > nr_clusters)) + return 1; + + off = blkid_le64(ns->mft_mirror_cluster_location) * + bytes_per_sector * sectors_per_cluster; + + buf_mft = get_buffer(probe, off, mft_record_size); + if (!buf_mft) + return 1; + + if (memcmp(buf_mft, "FILE", 4)) + return 1; + + off = blkid_le64(ns->mft_cluster_location) * bytes_per_sector * + sectors_per_cluster; + + buf_mft = get_buffer(probe, off, mft_record_size); + if (!buf_mft) + return 1; + + if (memcmp(buf_mft, "FILE", 4)) + return 1; + + off += MFT_RECORD_VOLUME * mft_record_size; + + buf_mft = get_buffer(probe, off, mft_record_size); + if (!buf_mft) + return 1; + + if (memcmp(buf_mft, "FILE", 4)) + return 1; + + mft = (struct master_file_table_record *) buf_mft; + + attr_off = blkid_le16(mft->attrs_offset); + label_str[0] = 0; + + while (1) { + attr = (struct file_attribute *) (buf_mft + attr_off); + attr_len = blkid_le16(attr->len); + attr_type = blkid_le32(attr->type); + val_off = blkid_le16(attr->value_offset); + val_len = blkid_le32(attr->value_len); + + attr_off += attr_len; + + if ((attr_off > mft_record_size) || + (attr_len == 0)) + break; + + if (attr_type == MFT_RECORD_ATTR_END) + break; + + if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) { + if (val_len > sizeof(label_str)) + val_len = sizeof(label_str)-1; + + for (i=0, cp=label_str; i < val_len; i+=2,cp++) { + val = ((__u8 *) attr) + val_off + i; + *cp = val[0]; + if (val[1]) + *cp = '?'; + } + *cp = 0; + } + } + + sprintf(uuid_str, "%016llX", blkid_le64(ns->volume_serial)); + blkid_set_tag(probe->dev, "UUID", uuid_str, 0); + if (label_str[0]) + blkid_set_tag(probe->dev, "LABEL", label_str, 0); + return 0; +} + + +static int probe_xfs(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct xfs_super_block *xs; + const char *label = 0; + + xs = (struct xfs_super_block *)buf; + + if (strlen(xs->xs_fname)) + label = xs->xs_fname; + blkid_set_tag(probe->dev, "LABEL", label, sizeof(xs->xs_fname)); + set_uuid(probe->dev, xs->xs_uuid, 0); + return 0; +} + +static int probe_reiserfs(struct blkid_probe *probe, + struct blkid_magic *id, unsigned char *buf) +{ + struct reiserfs_super_block *rs = (struct reiserfs_super_block *) buf; + unsigned int blocksize; + const char *label = 0; + + blocksize = blkid_le16(rs->rs_blocksize); + + /* The blocksize must be at least 1k */ + if ((blocksize >> 10) == 0) + return -BLKID_ERR_PARAM; + + /* If the superblock is inside the journal, we have the wrong one */ + if (id->bim_kboff/(blocksize>>10) > blkid_le32(rs->rs_journal_block)) + return -BLKID_ERR_BIG; + + /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */ + if (id->bim_magic[6] == '2' || id->bim_magic[6] == '3') { + if (strlen(rs->rs_label)) + label = rs->rs_label; + set_uuid(probe->dev, rs->rs_uuid, 0); + } + blkid_set_tag(probe->dev, "LABEL", label, sizeof(rs->rs_label)); + + return 0; +} + +static int probe_reiserfs4(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct reiser4_super_block *rs4 = (struct reiser4_super_block *) buf; + const unsigned char *label = 0; + + if (strlen((char *) rs4->rs4_label)) + label = rs4->rs4_label; + set_uuid(probe->dev, rs4->rs4_uuid, 0); + blkid_set_tag(probe->dev, "LABEL", (const char *) label, + sizeof(rs4->rs4_label)); + + return 0; +} + +static int probe_jfs(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct jfs_super_block *js; + const char *label = 0; + + js = (struct jfs_super_block *)buf; + + if (blkid_le32(js->js_bsize) != (1U << blkid_le16(js->js_l2bsize))) + return 1; + + if (blkid_le32(js->js_pbsize) != (1U << blkid_le16(js->js_l2pbsize))) + return 1; + + if ((blkid_le16(js->js_l2bsize) - blkid_le16(js->js_l2pbsize)) != + blkid_le16(js->js_l2bfactor)) + return 1; + + if (strlen((char *) js->js_label)) + label = (char *) js->js_label; + blkid_set_tag(probe->dev, "LABEL", label, sizeof(js->js_label)); + set_uuid(probe->dev, js->js_uuid, 0); + return 0; +} + +static int probe_zfs(struct blkid_probe *probe __BLKID_ATTR((unused)), + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf __BLKID_ATTR((unused))) +{ +#if 0 + char *vdev_label; + const char *pool_name = 0; + + /* read nvpair data for pool name, pool GUID (complex) */ + blkid_set_tag(probe->dev, "LABEL", pool_name, sizeof(pool_name)); + set_uuid(probe->dev, pool_guid, 0); +#endif + return 0; +} + +static int probe_luks(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + char uuid[40]; + + /* 168 is the offset to the 40 character uuid: + * http://luks.endorphin.org/LUKS-on-disk-format.pdf */ + strncpy(uuid, (char *) buf+168, 40); + blkid_set_tag(probe->dev, "UUID", uuid, sizeof(uuid)); + return 0; +} + +static int probe_romfs(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct romfs_super_block *ros; + const char *label = 0; + + ros = (struct romfs_super_block *)buf; + + if (strlen((char *) ros->ros_volume)) + label = (char *) ros->ros_volume; + blkid_set_tag(probe->dev, "LABEL", label, 0); + return 0; +} + +static int probe_cramfs(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct cramfs_super_block *csb; + const char *label = 0; + + csb = (struct cramfs_super_block *)buf; + + if (strlen((char *) csb->name)) + label = (char *) csb->name; + blkid_set_tag(probe->dev, "LABEL", label, 0); + return 0; +} + +static int probe_swap0(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf __BLKID_ATTR((unused))) +{ + blkid_set_tag(probe->dev, "UUID", 0, 0); + blkid_set_tag(probe->dev, "LABEL", 0, 0); + return 0; +} + +static int probe_swap1(struct blkid_probe *probe, + struct blkid_magic *id, + unsigned char *buf __BLKID_ATTR((unused))) +{ + struct swap_id_block *sws; + + probe_swap0(probe, id, buf); + /* + * Version 1 swap headers are always located at offset of 1024 + * bytes, although the swap signature itself is located at the + * end of the page (which may vary depending on hardware + * pagesize). + */ + sws = (struct swap_id_block *) get_buffer(probe, 1024, 1024); + if (!sws) + return 1; + + /* check for wrong version or zeroed pagecount, for sanity */ + if (!memcmp(id->bim_magic, "SWAPSPACE2", id->bim_len) && + (sws->sws_version != 1 || sws->sws_lastpage == 0)) + return 1; + + /* arbitrary sanity check.. is there any garbage down there? */ + if (sws->sws_pad[32] == 0 && sws->sws_pad[33] == 0) { + if (sws->sws_volume[0]) + blkid_set_tag(probe->dev, "LABEL", sws->sws_volume, + sizeof(sws->sws_volume)); + if (sws->sws_uuid[0]) + set_uuid(probe->dev, sws->sws_uuid, 0); + } + return 0; +} + +static int probe_iso9660(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct iso_volume_descriptor *iso; + const unsigned char *label; + + iso = (struct iso_volume_descriptor *) buf; + label = iso->volume_id; + + blkid_set_tag(probe->dev, "LABEL", (const char *) label, + figure_label_len(label, 32)); + return 0; +} + + +static const char +*udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02", + "NSR03", "TEA01", 0 }; + +static int probe_udf(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf __BLKID_ATTR((unused))) +{ + int j, bs; + struct iso_volume_descriptor *isosb; + const char ** m; + + /* determine the block size by scanning in 2K increments + (block sizes larger than 2K will be null padded) */ + for (bs = 1; bs < 16; bs++) { + isosb = (struct iso_volume_descriptor *) + get_buffer(probe, (blkid_loff_t) bs*2048+32768, + sizeof(*isosb)); + if (!isosb) + return 1; + if (isosb->vd_id[0]) + break; + } + + /* Scan up to another 64 blocks looking for additional VSD's */ + for (j = 1; j < 64; j++) { + if (j > 1) { + isosb = (struct iso_volume_descriptor *) + get_buffer(probe, j*bs*2048+32768, + sizeof(*isosb)); + if (!isosb) + return 1; + } + /* If we find NSR0x then call it udf: + NSR01 for UDF 1.00 + NSR02 for UDF 1.50 + NSR03 for UDF 2.00 */ + if (!memcmp(isosb->vd_id, "NSR0", 4)) + return probe_iso9660(probe, id, buf); + for (m = udf_magic; *m; m++) + if (!memcmp(*m, isosb->vd_id, 5)) + break; + if (*m == 0) + return 1; + } + return 1; +} + +static int probe_ocfs(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct ocfs_volume_header ovh; + struct ocfs_volume_label ovl; + __u32 major; + + memcpy(&ovh, buf, sizeof(ovh)); + memcpy(&ovl, buf+512, sizeof(ovl)); + + major = ocfsmajor(ovh); + if (major == 1) + blkid_set_tag(probe->dev,"SEC_TYPE","ocfs1",sizeof("ocfs1")); + else if (major >= 9) + blkid_set_tag(probe->dev,"SEC_TYPE","ntocfs",sizeof("ntocfs")); + + blkid_set_tag(probe->dev, "LABEL", ovl.label, ocfslabellen(ovl)); + blkid_set_tag(probe->dev, "MOUNT", ovh.mount, ocfsmountlen(ovh)); + set_uuid(probe->dev, ovl.vol_id, 0); + return 0; +} + +static int probe_ocfs2(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct ocfs2_super_block *osb; + + osb = (struct ocfs2_super_block *)buf; + + blkid_set_tag(probe->dev, "LABEL", osb->s_label, sizeof(osb->s_label)); + set_uuid(probe->dev, osb->s_uuid, 0); + return 0; +} + +static int probe_oracleasm(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct oracle_asm_disk_label *dl; + + dl = (struct oracle_asm_disk_label *)buf; + + blkid_set_tag(probe->dev, "LABEL", dl->dl_id, sizeof(dl->dl_id)); + return 0; +} + +static int probe_gfs(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct gfs2_sb *sbd; + const char *label = 0; + + sbd = (struct gfs2_sb *)buf; + + if (blkid_be32(sbd->sb_fs_format) == GFS_FORMAT_FS && + blkid_be32(sbd->sb_multihost_format) == GFS_FORMAT_MULTI) + { + blkid_set_tag(probe->dev, "UUID", 0, 0); + + if (strlen(sbd->sb_locktable)) + label = sbd->sb_locktable; + blkid_set_tag(probe->dev, "LABEL", label, sizeof(sbd->sb_locktable)); + return 0; + } + return 1; +} + +static int probe_gfs2(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct gfs2_sb *sbd; + const char *label = 0; + + sbd = (struct gfs2_sb *)buf; + + if (blkid_be32(sbd->sb_fs_format) == GFS2_FORMAT_FS && + blkid_be32(sbd->sb_multihost_format) == GFS2_FORMAT_MULTI) + { + blkid_set_tag(probe->dev, "UUID", 0, 0); + + if (strlen(sbd->sb_locktable)) + label = sbd->sb_locktable; + blkid_set_tag(probe->dev, "LABEL", label, sizeof(sbd->sb_locktable)); + return 0; + } + return 1; +} + +static void unicode_16be_to_utf8(unsigned char *str, int out_len, + const unsigned char *buf, int in_len) +{ + int i, j; + unsigned int c; + + for (i = j = 0; i + 2 <= in_len; i += 2) { + c = (buf[i] << 8) | buf[i+1]; + if (c == 0) { + str[j] = '\0'; + break; + } else if (c < 0x80) { + if (j+1 >= out_len) + break; + str[j++] = (unsigned char) c; + } else if (c < 0x800) { + if (j+2 >= out_len) + break; + str[j++] = (unsigned char) (0xc0 | (c >> 6)); + str[j++] = (unsigned char) (0x80 | (c & 0x3f)); + } else { + if (j+3 >= out_len) + break; + str[j++] = (unsigned char) (0xe0 | (c >> 12)); + str[j++] = (unsigned char) (0x80 | ((c >> 6) & 0x3f)); + str[j++] = (unsigned char) (0x80 | (c & 0x3f)); + } + } + str[j] = '\0'; +} + +static void unicode_16le_to_utf8(unsigned char *str, int out_len, + const unsigned char *buf, int in_len) +{ + int i, j; + unsigned int c; + + for (i = j = 0; i + 2 <= in_len; i += 2) { + c = (buf[i+1] << 8) | buf[i]; + if (c == 0) { + str[j] = '\0'; + break; + } else if (c < 0x80) { + if (j+1 >= out_len) + break; + str[j++] = (unsigned char) c; + } else if (c < 0x800) { + if (j+2 >= out_len) + break; + str[j++] = (unsigned char) (0xc0 | (c >> 6)); + str[j++] = (unsigned char) (0x80 | (c & 0x3f)); + } else { + if (j+3 >= out_len) + break; + str[j++] = (unsigned char) (0xe0 | (c >> 12)); + str[j++] = (unsigned char) (0x80 | ((c >> 6) & 0x3f)); + str[j++] = (unsigned char) (0x80 | (c & 0x3f)); + } + } + str[j] = '\0'; +} + +static int probe_hfs(struct blkid_probe *probe __BLKID_ATTR((unused)), + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct hfs_mdb *hfs = (struct hfs_mdb *)buf; + unsigned long long *uuid_ptr; + char uuid_str[17]; + __u64 uuid; + + if ((memcmp(hfs->embed_sig, "H+", 2) == 0) || + (memcmp(hfs->embed_sig, "HX", 2) == 0)) + return 1; /* Not hfs, but an embedded HFS+ */ + + uuid_ptr = (unsigned long long *)hfs->finder_info.id; + uuid = blkid_le64(*uuid_ptr); + if (uuid) { + sprintf(uuid_str, "%016llX", uuid); + blkid_set_tag(probe->dev, "UUID", uuid_str, 0); + } + blkid_set_tag(probe->dev, "LABEL", (char *)hfs->label, hfs->label_len); + return 0; +} + + +#define HFSPLUS_SECTOR_SIZE 512 + +static int probe_hfsplus(struct blkid_probe *probe, + struct blkid_magic *id, + unsigned char *buf) +{ + struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; + struct hfsplus_bnode_descriptor *descr; + struct hfsplus_bheader_record *bnode; + struct hfsplus_catalog_key *key; + struct hfsplus_vol_header *hfsplus; + struct hfs_mdb *sbd = (struct hfs_mdb *) buf; + unsigned int alloc_block_size; + unsigned int alloc_first_block; + unsigned int embed_first_block; + unsigned int off = 0; + unsigned int blocksize; + unsigned int cat_block; + unsigned int ext_block_start; + unsigned int ext_block_count; + unsigned int record_count; + unsigned int leaf_node_head; + unsigned int leaf_node_count; + unsigned int leaf_node_size; + unsigned int leaf_block; + unsigned int label_len; + unsigned long long *uuid_ptr; + __u64 leaf_off, uuid; + char uuid_str[17], label[512]; + int ext; + + /* Check for a HFS+ volume embedded in a HFS volume */ + if (memcmp(sbd->signature, "BD", 2) == 0) { + if ((memcmp(sbd->embed_sig, "H+", 2) != 0) && + (memcmp(sbd->embed_sig, "HX", 2) != 0)) + /* This must be an HFS volume, so fail */ + return 1; + + alloc_block_size = blkid_be32(sbd->al_blk_size); + alloc_first_block = blkid_be16(sbd->al_bl_st); + embed_first_block = blkid_be16(sbd->embed_startblock); + off = (alloc_first_block * 512) + + (embed_first_block * alloc_block_size); + buf = get_buffer(probe, off + (id->bim_kboff * 1024), + sizeof(*sbd)); + if (!buf) + return 1; + + hfsplus = (struct hfsplus_vol_header *) buf; + } + + hfsplus = (struct hfsplus_vol_header *) buf; + + if ((memcmp(hfsplus->signature, "H+", 2) != 0) && + (memcmp(hfsplus->signature, "HX", 2) != 0)) + return 1; + + uuid_ptr = (unsigned long long *)hfsplus->finder_info.id; + uuid = blkid_le64(*uuid_ptr); + if (uuid) { + sprintf(uuid_str, "%016llX", uuid); + blkid_set_tag(probe->dev, "UUID", uuid_str, 0); + } + + blocksize = blkid_be32(hfsplus->blocksize); + if (blocksize < HFSPLUS_SECTOR_SIZE) + return 1; + + memcpy(extents, hfsplus->cat_file.extents, sizeof(extents)); + cat_block = blkid_be32(extents[0].start_block); + + buf = get_buffer(probe, off + ((__u64) cat_block * blocksize), 0x2000); + if (!buf) + return 0; + + bnode = (struct hfsplus_bheader_record *) + &buf[sizeof(struct hfsplus_bnode_descriptor)]; + + leaf_node_head = blkid_be32(bnode->leaf_head); + leaf_node_size = blkid_be16(bnode->node_size); + leaf_node_count = blkid_be32(bnode->leaf_count); + if (leaf_node_count == 0) + return 0; + + leaf_block = (leaf_node_head * leaf_node_size) / blocksize; + + /* get physical location */ + for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) { + ext_block_start = blkid_be32(extents[ext].start_block); + ext_block_count = blkid_be32(extents[ext].block_count); + if (ext_block_count == 0) + return 0; + + /* this is our extent */ + if (leaf_block < ext_block_count) + break; + + leaf_block -= ext_block_count; + } + if (ext == HFSPLUS_EXTENT_COUNT) + return 0; + + leaf_off = (__u64) (ext_block_start + leaf_block) * blocksize; + + buf = get_buffer(probe, off + leaf_off, leaf_node_size); + if (!buf) + return 0; + + descr = (struct hfsplus_bnode_descriptor *) buf; + record_count = blkid_be16(descr->num_recs); + if (record_count == 0) + return 0; + + if (descr->type != HFS_NODE_LEAF) + return 0; + + key = (struct hfsplus_catalog_key *) + &buf[sizeof(struct hfsplus_bnode_descriptor)]; + + if (blkid_be32(key->parent_id) != HFSPLUS_POR_CNID) + return 0; + + label_len = blkid_be16(key->unicode_len) * 2; + unicode_16be_to_utf8((unsigned char *)label, sizeof(label), + key->unicode, label_len); + blkid_set_tag(probe->dev, "LABEL", label, 0); + return 0; +} + +#define LVM2_LABEL_SIZE 512 +static unsigned int lvm2_calc_crc(const void *buf, unsigned int size) +{ + static const unsigned int crctab[] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + unsigned int i, crc = 0xf597a6cf; + const __u8 *data = (const __u8 *) buf; + + for (i = 0; i < size; i++) { + crc ^= *data++; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + } + return crc; +} + +static int probe_lvm2(struct blkid_probe *probe, + struct blkid_magic *id, + unsigned char *buf) +{ + int sector = (id->bim_kboff) << 1; + struct lvm2_pv_label_header *label= (struct lvm2_pv_label_header *)buf; + char *p, *q, uuid[40]; + unsigned int i, b; + + /* buf is at 0k or 1k offset; find label inside */ + if (memcmp(buf, "LABELONE", 8) == 0) { + label = (struct lvm2_pv_label_header *)buf; + } else if (memcmp(buf + 512, "LABELONE", 8) == 0) { + label = (struct lvm2_pv_label_header *)(buf + 512); + sector++; + } else { + return 1; + } + + if (blkid_le64(label->sector_xl) != (unsigned) sector) { + DBG(DEBUG_PROBE, + printf("LVM2: label for sector %llu found at sector %d\n", + blkid_le64(label->sector_xl), sector)); + return 1; + } + + if (lvm2_calc_crc(&label->offset_xl, LVM2_LABEL_SIZE - + ((char *)&label->offset_xl - (char *)label)) != + blkid_le32(label->crc_xl)) { + DBG(DEBUG_PROBE, + printf("LVM2: label checksum incorrect at sector %d\n", + sector)); + return 1; + } + + for (i=0, b=1, p=uuid, q= (char *) label->pv_uuid; i < LVM2_ID_LEN; + i++, b <<= 1) { + if (b & 0x4444440) + *p++ = '-'; + *p++ = *q++; + } + + blkid_set_tag(probe->dev, "UUID", uuid, LVM2_ID_LEN+6); + + return 0; +} + +static int probe_btrfs(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct btrfs_super_block *bs; + const char *label = 0; + + bs = (struct btrfs_super_block *)buf; + + if (strlen(bs->label)) + label = bs->label; + blkid_set_tag(probe->dev, "LABEL", label, sizeof(bs->label)); + set_uuid(probe->dev, bs->fsid, 0); + return 0; +} + +static int probe_f2fs(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct f2fs_super_block *bs; + + bs = (struct f2fs_super_block *)buf; + set_uuid(probe->dev, bs->uuid, 0); + return 0; +} + +static uint64_t exfat_block_to_offset(const struct exfat_super_block *sb, + uint64_t block) +{ + return block << sb->block_bits; +} + +static uint64_t exfat_cluster_to_block(const struct exfat_super_block *sb, + uint32_t cluster) +{ + return sb->cluster_block_start + + ((uint64_t)(cluster - EXFAT_FIRST_DATA_CLUSTER) << sb->bpc_bits); +} + +static uint64_t exfat_cluster_to_offset(const struct exfat_super_block *sb, + uint32_t cluster) +{ + return exfat_block_to_offset(sb, exfat_cluster_to_block(sb, cluster)); +} + +static uint32_t exfat_next_cluster(struct blkid_probe *probe, + const struct exfat_super_block *sb, + uint32_t cluster) +{ + uint32_t *next; + uint64_t offset; + + offset = exfat_block_to_offset(sb, sb->fat_block_start) + + (uint64_t) cluster * sizeof (cluster); + next = (uint32_t *)get_buffer(probe, offset, sizeof (uint32_t)); + + return next ? *next : 0; +} + +static struct exfat_entry_label *find_exfat_entry_label( + struct blkid_probe *probe, const struct exfat_super_block *sb) +{ + uint32_t cluster = sb->rootdir_cluster; + uint64_t offset = exfat_cluster_to_offset(sb, cluster); + uint8_t *entry; + const size_t max_iter = 10000; + size_t i = 0; + + for (; i < max_iter; ++i) { + entry = (uint8_t *)get_buffer(probe, offset, EXFAT_ENTRY_SIZE); + if (!entry) + return NULL; + if (entry[0] == EXFAT_ENTRY_EOD) + return NULL; + if (entry[0] == EXFAT_ENTRY_LABEL) + return (struct exfat_entry_label*) entry; + + offset += EXFAT_ENTRY_SIZE; + if (offset % CLUSTER_SIZE(sb) == 0) { + cluster = exfat_next_cluster(probe, sb, cluster); + if (cluster < EXFAT_FIRST_DATA_CLUSTER) + return NULL; + if (cluster > EXFAT_LAST_DATA_CLUSTER) + return NULL; + offset = exfat_cluster_to_offset(sb, cluster); + } + } + + return NULL; +} + +static int probe_exfat(struct blkid_probe *probe, struct blkid_magic *id, + unsigned char *buf) +{ + struct exfat_super_block *sb; + struct exfat_entry_label *label; + uuid_t uuid; + + sb = (struct exfat_super_block *)buf; + if (!sb || !CLUSTER_SIZE(sb)) { + DBG(DEBUG_PROBE, printf("bad exfat superblock.\n")); + return errno ? - errno : 1; + } + + label = find_exfat_entry_label(probe, sb); + if (label) { + char utf8_label[128]; + unicode_16le_to_utf8(utf8_label, sizeof(utf8_label), label->name, label->length * 2); + blkid_set_tag(probe->dev, "LABEL", utf8_label, 0); + } else { + blkid_set_tag(probe->dev, "LABEL", "disk", 4); + } + + memset(uuid, 0, sizeof (uuid)); + snprintf(uuid, sizeof (uuid), "%02hhX%02hhX-%02hhX%02hhX", + sb->volume_serial[3], sb->volume_serial[2], + sb->volume_serial[1], sb->volume_serial[0]); + blkid_set_tag(probe->dev, "UUID", uuid, strlen(uuid)); + + return 0; +} + +/* + * Various filesystem magics that we can check for. Note that kboff and + * sboff are in kilobytes and bytes respectively. All magics are in + * byte strings so we don't worry about endian issues. + */ +static struct blkid_magic type_array[] = { +/* type kboff sboff len magic probe */ + { "oracleasm", 0, 32, 8, "ORCLDISK", probe_oracleasm }, + { "ntfs", 0, 3, 8, "NTFS ", probe_ntfs }, + { "jbd", 1, 0x38, 2, "\123\357", probe_jbd }, + { "ext4dev", 1, 0x38, 2, "\123\357", probe_ext4dev }, + { "ext4", 1, 0x38, 2, "\123\357", probe_ext4 }, + { "ext3", 1, 0x38, 2, "\123\357", probe_ext3 }, + { "ext2", 1, 0x38, 2, "\123\357", probe_ext2 }, + { "reiserfs", 8, 0x34, 8, "ReIsErFs", probe_reiserfs }, + { "reiserfs", 64, 0x34, 9, "ReIsEr2Fs", probe_reiserfs }, + { "reiserfs", 64, 0x34, 9, "ReIsEr3Fs", probe_reiserfs }, + { "reiserfs", 64, 0x34, 8, "ReIsErFs", probe_reiserfs }, + { "reiserfs", 8, 20, 8, "ReIsErFs", probe_reiserfs }, + { "reiser4", 64, 0, 7, "ReIsEr4", probe_reiserfs4 }, + { "gfs2", 64, 0, 4, "\x01\x16\x19\x70", probe_gfs2 }, + { "gfs", 64, 0, 4, "\x01\x16\x19\x70", probe_gfs }, + { "vfat", 0, 0x52, 5, "MSWIN", probe_fat }, + { "vfat", 0, 0x52, 8, "FAT32 ", probe_fat }, + { "vfat", 0, 0x36, 5, "MSDOS", probe_fat }, + { "vfat", 0, 0x36, 8, "FAT16 ", probe_fat }, + { "vfat", 0, 0x36, 8, "FAT12 ", probe_fat }, + { "vfat", 0, 0, 1, "\353", probe_fat_nomagic }, + { "vfat", 0, 0, 1, "\351", probe_fat_nomagic }, + { "vfat", 0, 0x1fe, 2, "\125\252", probe_fat_nomagic }, + { "minix", 1, 0x10, 2, "\177\023", 0 }, + { "minix", 1, 0x10, 2, "\217\023", 0 }, + { "minix", 1, 0x10, 2, "\150\044", 0 }, + { "minix", 1, 0x10, 2, "\170\044", 0 }, + { "vxfs", 1, 0, 4, "\365\374\001\245", 0 }, + { "xfs", 0, 0, 4, "XFSB", probe_xfs }, + { "romfs", 0, 0, 8, "-rom1fs-", probe_romfs }, + { "bfs", 0, 0, 4, "\316\372\173\033", 0 }, + { "cramfs", 0, 0, 4, "E=\315\050", probe_cramfs }, + { "qnx4", 0, 4, 6, "QNX4FS", 0 }, + { "udf", 32, 1, 5, "BEA01", probe_udf }, + { "udf", 32, 1, 5, "BOOT2", probe_udf }, + { "udf", 32, 1, 5, "CD001", probe_udf }, + { "udf", 32, 1, 5, "CDW02", probe_udf }, + { "udf", 32, 1, 5, "NSR02", probe_udf }, + { "udf", 32, 1, 5, "NSR03", probe_udf }, + { "udf", 32, 1, 5, "TEA01", probe_udf }, + { "iso9660", 32, 1, 5, "CD001", probe_iso9660 }, + { "iso9660", 32, 9, 5, "CDROM", probe_iso9660 }, + { "jfs", 32, 0, 4, "JFS1", probe_jfs }, + /* ZFS has 128 root blocks (#4 is the first used), check only 6 of them */ + { "zfs", 128, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs }, + { "zfs", 128, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs }, + { "zfs", 132, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs }, + { "zfs", 132, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs }, + { "zfs", 136, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs }, + { "zfs", 136, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs }, + { "zfs", 384, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs }, + { "zfs", 384, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs }, + { "zfs", 388, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs }, + { "zfs", 388, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs }, + { "zfs", 392, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs }, + { "zfs", 392, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs }, + { "hfsplus", 1, 0, 2, "BD", probe_hfsplus }, + { "hfsplus", 1, 0, 2, "H+", probe_hfsplus }, + { "hfsplus", 1, 0, 2, "HX", probe_hfsplus }, + { "hfs", 1, 0, 2, "BD", probe_hfs }, + { "ufs", 8, 0x55c, 4, "T\031\001\000", 0 }, + { "hpfs", 8, 0, 4, "I\350\225\371", 0 }, + { "sysv", 0, 0x3f8, 4, "\020~\030\375", 0 }, + { "swap", 0, 0xff6, 10, "SWAP-SPACE", probe_swap0 }, + { "swap", 0, 0xff6, 10, "SWAPSPACE2", probe_swap1 }, + { "swsuspend", 0, 0xff6, 9, "S1SUSPEND", probe_swap1 }, + { "swsuspend", 0, 0xff6, 9, "S2SUSPEND", probe_swap1 }, + { "swsuspend", 0, 0xff6, 9, "ULSUSPEND", probe_swap1 }, + { "swap", 0, 0x1ff6, 10, "SWAP-SPACE", probe_swap0 }, + { "swap", 0, 0x1ff6, 10, "SWAPSPACE2", probe_swap1 }, + { "swsuspend", 0, 0x1ff6, 9, "S1SUSPEND", probe_swap1 }, + { "swsuspend", 0, 0x1ff6, 9, "S2SUSPEND", probe_swap1 }, + { "swsuspend", 0, 0x1ff6, 9, "ULSUSPEND", probe_swap1 }, + { "swap", 0, 0x3ff6, 10, "SWAP-SPACE", probe_swap0 }, + { "swap", 0, 0x3ff6, 10, "SWAPSPACE2", probe_swap1 }, + { "swsuspend", 0, 0x3ff6, 9, "S1SUSPEND", probe_swap1 }, + { "swsuspend", 0, 0x3ff6, 9, "S2SUSPEND", probe_swap1 }, + { "swsuspend", 0, 0x3ff6, 9, "ULSUSPEND", probe_swap1 }, + { "swap", 0, 0x7ff6, 10, "SWAP-SPACE", probe_swap0 }, + { "swap", 0, 0x7ff6, 10, "SWAPSPACE2", probe_swap1 }, + { "swsuspend", 0, 0x7ff6, 9, "S1SUSPEND", probe_swap1 }, + { "swsuspend", 0, 0x7ff6, 9, "S2SUSPEND", probe_swap1 }, + { "swsuspend", 0, 0x7ff6, 9, "ULSUSPEND", probe_swap1 }, + { "swap", 0, 0xfff6, 10, "SWAP-SPACE", probe_swap0 }, + { "swap", 0, 0xfff6, 10, "SWAPSPACE2", probe_swap1 }, + { "swsuspend", 0, 0xfff6, 9, "S1SUSPEND", probe_swap1 }, + { "swsuspend", 0, 0xfff6, 9, "S2SUSPEND", probe_swap1 }, + { "swsuspend", 0, 0xfff6, 9, "ULSUSPEND", probe_swap1 }, + { "ocfs", 0, 8, 9, "OracleCFS", probe_ocfs }, + { "ocfs2", 1, 0, 6, "OCFSV2", probe_ocfs2 }, + { "ocfs2", 2, 0, 6, "OCFSV2", probe_ocfs2 }, + { "ocfs2", 4, 0, 6, "OCFSV2", probe_ocfs2 }, + { "ocfs2", 8, 0, 6, "OCFSV2", probe_ocfs2 }, + { "crypt_LUKS", 0, 0, 6, "LUKS\xba\xbe", probe_luks }, + { "squashfs", 0, 0, 4, "sqsh", 0 }, + { "squashfs", 0, 0, 4, "hsqs", 0 }, + { "lvm2pv", 0, 0x218, 8, "LVM2 001", probe_lvm2 }, + { "lvm2pv", 0, 0x018, 8, "LVM2 001", probe_lvm2 }, + { "lvm2pv", 1, 0x018, 8, "LVM2 001", probe_lvm2 }, + { "lvm2pv", 1, 0x218, 8, "LVM2 001", probe_lvm2 }, + { "btrfs", 64, 0x40, 8, "_BHRfS_M", probe_btrfs }, + { "f2fs", 1, 0, 4, "\x10\x20\xf5\xf2", probe_f2fs }, + { "exfat", 0, 3, 8, "EXFAT ", probe_exfat }, + { NULL, 0, 0, 0, NULL, NULL } +}; + +/* + * Verify that the data in dev is consistent with what is on the actual + * block device (using the devname field only). Normally this will be + * called when finding items in the cache, but for long running processes + * is also desirable to revalidate an item before use. + * + * If we are unable to revalidate the data, we return the old data and + * do not set the BLKID_BID_FL_VERIFIED flag on it. + */ +blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) +{ + struct blkid_magic *id; + struct blkid_probe probe; + blkid_tag_iterate iter; + unsigned char *buf; + const char *type, *value; + struct stat st; + time_t now; + double diff; + int idx; + + if (!dev) + return NULL; + + now = time(0); + diff = difftime(now, dev->bid_time); + + if (stat(dev->bid_name, &st) < 0) { + DBG(DEBUG_PROBE, + printf("blkid_verify: error %s (%d) while " + "trying to stat %s\n", strerror(errno), errno, + dev->bid_name)); + open_err: + if ((errno == EPERM) || (errno == EACCES) || (errno == ENOENT)) { + /* We don't have read permission, just return cache data. */ + DBG(DEBUG_PROBE, printf("returning unverified data for %s\n", + dev->bid_name)); + return dev; + } + blkid_free_dev(dev); + return NULL; + } + + if ((now >= dev->bid_time) && + (st.st_mtime <= dev->bid_time) && + ((diff < BLKID_PROBE_MIN) || + (dev->bid_flags & BLKID_BID_FL_VERIFIED && + diff < BLKID_PROBE_INTERVAL))) + return dev; + + DBG(DEBUG_PROBE, + printf("need to revalidate %s (cache time %lu, stat time %lu,\n\t" + "time since last check %lu)\n", + dev->bid_name, (unsigned long)dev->bid_time, + (unsigned long)st.st_mtime, (unsigned long)diff)); + + if ((probe.fd = open(dev->bid_name, O_RDONLY)) < 0) { + DBG(DEBUG_PROBE, printf("blkid_verify: error %s (%d) while " + "opening %s\n", strerror(errno), errno, + dev->bid_name)); + goto open_err; + } + + probe.cache = cache; + probe.dev = dev; + probe.sbbuf = 0; + probe.buf = 0; + probe.buf_max = 0; + + /* + * Iterate over the type array. If we already know the type, + * then try that first. If it doesn't work, then blow away + * the type information, and try again. + * + */ +try_again: + type = 0; + if (!dev->bid_type || !strcmp(dev->bid_type, "mdraid")) { + uuid_t uuid; + + if (check_mdraid(probe.fd, uuid) == 0) { + set_uuid(dev, uuid, 0); + type = "mdraid"; + goto found_type; + } + } + for (id = type_array; id->bim_type; id++) { + if (dev->bid_type && + strcmp(id->bim_type, dev->bid_type)) + continue; + + idx = id->bim_kboff + (id->bim_sboff >> 10); + buf = get_buffer(&probe, (__u64) idx << 10, 1024); + if (!buf) + continue; + + if (memcmp(id->bim_magic, buf + (id->bim_sboff & 0x3ff), + id->bim_len)) + continue; + + if ((id->bim_probe == NULL) || + (id->bim_probe(&probe, id, buf) == 0)) { + type = id->bim_type; + goto found_type; + } + } + + if (!id->bim_type && dev->bid_type) { + /* + * Zap the device filesystem information and try again + */ + DBG(DEBUG_PROBE, + printf("previous fs type %s not valid, " + "trying full probe\n", dev->bid_type)); + iter = blkid_tag_iterate_begin(dev); + while (blkid_tag_next(iter, &type, &value) == 0) + blkid_set_tag(dev, type, 0, 0); + blkid_tag_iterate_end(iter); + goto try_again; + } + + if (!dev->bid_type) { + blkid_free_dev(dev); + dev = 0; + goto found_type; + } + +found_type: + if (dev && type) { + dev->bid_devno = st.st_rdev; + dev->bid_time = time(0); + dev->bid_flags |= BLKID_BID_FL_VERIFIED; + cache->bic_flags |= BLKID_BIC_FL_CHANGED; + + blkid_set_tag(dev, "TYPE", type, 0); + + DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n", + dev->bid_name, (long long)st.st_rdev, type)); + } + + free(probe.sbbuf); + free(probe.buf); + if (probe.fd >= 0) + close(probe.fd); + + return dev; +} + +int blkid_known_fstype(const char *fstype) +{ + struct blkid_magic *id; + + for (id = type_array; id->bim_type; id++) { + if (strcmp(fstype, id->bim_type) == 0) + return 1; + } + return 0; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + blkid_dev dev; + blkid_cache cache; + int ret; + + if (argc != 2) { + fprintf(stderr, "Usage: %s device\n" + "Probe a single device to determine type\n", argv[0]); + exit(1); + } + if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL); + if (!dev) { + printf("%s: %s has an unsupported type\n", argv[0], argv[1]); + return (1); + } + printf("TYPE='%s'\n", dev->bid_type ? dev->bid_type : "(null)"); + if (dev->bid_label) + printf("LABEL='%s'\n", dev->bid_label); + if (dev->bid_uuid) + printf("UUID='%s'\n", dev->bid_uuid); + + blkid_free_dev(dev); + return (0); +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/probe.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/probe.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,895 @@ +/* + * probe.h - constants and on-disk structures for extracting device data + * + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#ifndef _BLKID_PROBE_H +#define _BLKID_PROBE_H + +#include + +#include + +struct blkid_magic; + +#define SB_BUFFER_SIZE 0x11000 + +struct blkid_probe { + int fd; + blkid_cache cache; + blkid_dev dev; + unsigned char *sbbuf; + size_t sb_valid; + unsigned char *buf; + size_t buf_max; +}; + +typedef int (*blkid_probe_t)(struct blkid_probe *probe, + struct blkid_magic *id, unsigned char *buf); + +struct blkid_magic { + const char *bim_type; /* type name for this magic */ + long bim_kboff; /* kilobyte offset of superblock */ + unsigned bim_sboff; /* byte offset within superblock */ + unsigned bim_len; /* length of magic */ + const char *bim_magic; /* magic string */ + blkid_probe_t bim_probe; /* probe function */ +}; + +/* + * Structures for each of the content types we want to extract information + * from. We do not necessarily need the magic field here, because we have + * already identified the content type before we get this far. It may still + * be useful if there are probe functions which handle multiple content types. + */ +struct ext2_super_block { + __u32 s_inodes_count; + __u32 s_blocks_count; + __u32 s_r_blocks_count; + __u32 s_free_blocks_count; + __u32 s_free_inodes_count; + __u32 s_first_data_block; + __u32 s_log_block_size; + __u32 s_dummy3[7]; + unsigned char s_magic[2]; + __u16 s_state; + __u32 s_dummy5[8]; + __u32 s_feature_compat; + __u32 s_feature_incompat; + __u32 s_feature_ro_compat; + unsigned char s_uuid[16]; + char s_volume_name[16]; + char s_last_mounted[64]; + __u32 s_algorithm_usage_bitmap; + __u8 s_prealloc_blocks; + __u8 s_prealloc_dir_blocks; + __u16 s_reserved_gdt_blocks; + __u8 s_journal_uuid[16]; + __u32 s_journal_inum; + __u32 s_journal_dev; + __u32 s_last_orphan; + __u32 s_hash_seed[4]; + __u8 s_def_hash_version; + __u8 s_jnl_backup_type; + __u16 s_reserved_word_pad; + __u32 s_default_mount_opts; + __u32 s_first_meta_bg; + __u32 s_mkfs_time; + __u32 s_jnl_blocks[17]; + __u32 s_blocks_count_hi; + __u32 s_r_blocks_count_hi; + __u32 s_free_blocks_hi; + __u16 s_min_extra_isize; + __u16 s_want_extra_isize; + __u32 s_flags; + __u16 s_raid_stride; + __u16 s_mmp_interval; + __u64 s_mmp_block; + __u32 s_raid_stripe_width; + __u32 s_reserved[163]; +}; + +/* for s_flags */ +#define EXT2_FLAGS_TEST_FILESYS 0x0004 + +/* for s_feature_compat */ +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 + +/* for s_feature_ro_compat */ +#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 +#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008 +#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 +#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020 +#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 +#define EXT4_FEATURE_RO_COMPAT_QUOTA 0x0100 +#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400 + +/* for s_feature_incompat */ +#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 +#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 +#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ +#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 +#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 +#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 + +#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT2_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ + EXT2_FEATURE_INCOMPAT_META_BG) +#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP +#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP + +#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT2_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT3_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ + EXT3_FEATURE_INCOMPAT_RECOVER| \ + EXT2_FEATURE_INCOMPAT_META_BG) +#define EXT3_FEATURE_INCOMPAT_UNSUPPORTED ~EXT3_FEATURE_INCOMPAT_SUPP +#define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT3_FEATURE_RO_COMPAT_SUPP + + +struct xfs_super_block { + unsigned char xs_magic[4]; + __u32 xs_blocksize; + __u64 xs_dblocks; + __u64 xs_rblocks; + __u32 xs_dummy1[2]; + unsigned char xs_uuid[16]; + __u32 xs_dummy2[15]; + char xs_fname[12]; + __u32 xs_dummy3[2]; + __u64 xs_icount; + __u64 xs_ifree; + __u64 xs_fdblocks; +}; + +struct reiserfs_super_block { + __u32 rs_blocks_count; + __u32 rs_free_blocks; + __u32 rs_root_block; + __u32 rs_journal_block; + __u32 rs_journal_dev; + __u32 rs_orig_journal_size; + __u32 rs_dummy2[5]; + __u16 rs_blocksize; + __u16 rs_dummy3[3]; + unsigned char rs_magic[12]; + __u32 rs_dummy4[5]; + unsigned char rs_uuid[16]; + char rs_label[16]; +}; + +struct reiser4_super_block { + unsigned char rs4_magic[16]; + __u16 rs4_dummy[2]; + unsigned char rs4_uuid[16]; + unsigned char rs4_label[16]; + __u64 rs4_dummy2; +}; + +struct jfs_super_block { + unsigned char js_magic[4]; + __u32 js_version; + __u64 js_size; + __u32 js_bsize; /* 4: aggregate block size in bytes */ + __u16 js_l2bsize; /* 2: log2 of s_bsize */ + __u16 js_l2bfactor; /* 2: log2(s_bsize/hardware block size) */ + __u32 js_pbsize; /* 4: hardware/LVM block size in bytes */ + __u16 js_l2pbsize; /* 2: log2 of s_pbsize */ + __u16 js_pad; /* 2: padding necessary for alignment */ + __u32 js_dummy2[26]; + unsigned char js_uuid[16]; + unsigned char js_label[16]; + unsigned char js_loguuid[16]; +}; + +struct romfs_super_block { + unsigned char ros_magic[8]; + __u32 ros_dummy1[2]; + unsigned char ros_volume[16]; +}; + +struct cramfs_super_block { + __u8 magic[4]; + __u32 size; + __u32 flags; + __u32 future; + __u8 signature[16]; + struct cramfs_info { + __u32 crc; + __u32 edition; + __u32 blocks; + __u32 files; + } info; + __u8 name[16]; +}; + +struct swap_id_block { +/* unsigned char sws_boot[1024]; */ + __u32 sws_version; + __u32 sws_lastpage; + __u32 sws_nrbad; + unsigned char sws_uuid[16]; + char sws_volume[16]; + unsigned char sws_pad[117]; + __u32 sws_badpg; +}; + +/* Yucky misaligned values */ +struct vfat_super_block { +/* 00*/ unsigned char vs_ignored[3]; +/* 03*/ unsigned char vs_sysid[8]; +/* 0b*/ unsigned char vs_sector_size[2]; +/* 0d*/ __u8 vs_cluster_size; +/* 0e*/ __u16 vs_reserved; +/* 10*/ __u8 vs_fats; +/* 11*/ unsigned char vs_dir_entries[2]; +/* 13*/ unsigned char vs_sectors[2]; +/* 15*/ unsigned char vs_media; +/* 16*/ __u16 vs_fat_length; +/* 18*/ __u16 vs_secs_track; +/* 1a*/ __u16 vs_heads; +/* 1c*/ __u32 vs_hidden; +/* 20*/ __u32 vs_total_sect; +/* 24*/ __u32 vs_fat32_length; +/* 28*/ __u16 vs_flags; +/* 2a*/ __u8 vs_version[2]; +/* 2c*/ __u32 vs_root_cluster; +/* 30*/ __u16 vs_insfo_sector; +/* 32*/ __u16 vs_backup_boot; +/* 34*/ __u16 vs_reserved2[6]; +/* 40*/ unsigned char vs_unknown[3]; +/* 43*/ unsigned char vs_serno[4]; +/* 47*/ unsigned char vs_label[11]; +/* 52*/ unsigned char vs_magic[8]; +/* 5a*/ unsigned char vs_dummy2[164]; +/*1fe*/ unsigned char vs_pmagic[2]; +}; + +/* Yucky misaligned values */ +struct msdos_super_block { +/* 00*/ unsigned char ms_ignored[3]; +/* 03*/ unsigned char ms_sysid[8]; +/* 0b*/ unsigned char ms_sector_size[2]; +/* 0d*/ __u8 ms_cluster_size; +/* 0e*/ __u16 ms_reserved; +/* 10*/ __u8 ms_fats; +/* 11*/ unsigned char ms_dir_entries[2]; +/* 13*/ unsigned char ms_sectors[2]; +/* 15*/ unsigned char ms_media; +/* 16*/ __u16 ms_fat_length; +/* 18*/ __u16 ms_secs_track; +/* 1a*/ __u16 ms_heads; +/* 1c*/ __u32 ms_hidden; +/* 20*/ __u32 ms_total_sect; +/* 24*/ unsigned char ms_unknown[3]; +/* 27*/ unsigned char ms_serno[4]; +/* 2b*/ unsigned char ms_label[11]; +/* 36*/ unsigned char ms_magic[8]; +/* 3d*/ unsigned char ms_dummy2[192]; +/*1fe*/ unsigned char ms_pmagic[2]; +}; + +struct vfat_dir_entry { + __u8 name[11]; + __u8 attr; + __u16 time_creat; + __u16 date_creat; + __u16 time_acc; + __u16 date_acc; + __u16 cluster_high; + __u16 time_write; + __u16 date_write; + __u16 cluster_low; + __u32 size; +}; + +/* maximum number of clusters */ +#define FAT12_MAX 0xFF4 +#define FAT16_MAX 0xFFF4 +#define FAT32_MAX 0x0FFFFFF6 + +struct minix_super_block { + __u16 ms_ninodes; + __u16 ms_nzones; + __u16 ms_imap_blocks; + __u16 ms_zmap_blocks; + __u16 ms_firstdatazone; + __u16 ms_log_zone_size; + __u32 ms_max_size; + unsigned char ms_magic[2]; + __u16 ms_state; + __u32 ms_zones; +}; + +struct mdp_superblock_s { + __u32 md_magic; + __u32 major_version; + __u32 minor_version; + __u32 patch_version; + __u32 gvalid_words; + __u32 set_uuid0; + __u32 ctime; + __u32 level; + __u32 size; + __u32 nr_disks; + __u32 raid_disks; + __u32 md_minor; + __u32 not_persistent; + __u32 set_uuid1; + __u32 set_uuid2; + __u32 set_uuid3; +}; + +struct hfs_super_block { + char h_magic[2]; + char h_dummy[18]; + __u32 h_blksize; +}; + +struct ocfs_volume_header { + unsigned char minor_version[4]; + unsigned char major_version[4]; + unsigned char signature[128]; + char mount[128]; + unsigned char mount_len[2]; +}; + +struct ocfs_volume_label { + unsigned char disk_lock[48]; + char label[64]; + unsigned char label_len[2]; + unsigned char vol_id[16]; + unsigned char vol_id_len[2]; +}; + +#define ocfsmajor(o) ((__u32)o.major_version[0] \ + + (((__u32) o.major_version[1]) << 8) \ + + (((__u32) o.major_version[2]) << 16) \ + + (((__u32) o.major_version[3]) << 24)) +#define ocfslabellen(o) ((__u32)o.label_len[0] + (((__u32) o.label_len[1]) << 8)) +#define ocfsmountlen(o) ((__u32)o.mount_len[0] + (((__u32) o.mount_len[1])<<8)) + +#define OCFS_MAGIC "OracleCFS" + +struct ocfs2_super_block { + unsigned char signature[8]; + unsigned char s_dummy1[184]; + unsigned char s_dummy2[80]; + char s_label[64]; + unsigned char s_uuid[16]; +}; + +#define OCFS2_MIN_BLOCKSIZE 512 +#define OCFS2_MAX_BLOCKSIZE 4096 + +#define OCFS2_SUPER_BLOCK_BLKNO 2 + +#define OCFS2_SUPER_BLOCK_SIGNATURE "OCFSV2" + +struct oracle_asm_disk_label { + char dummy[32]; + char dl_tag[8]; + char dl_id[24]; +}; + +#define ORACLE_ASM_DISK_LABEL_MARKED "ORCLDISK" +#define ORACLE_ASM_DISK_LABEL_OFFSET 32 + +struct iso_volume_descriptor { + unsigned char vd_type; + unsigned char vd_id[5]; + unsigned char vd_version; + unsigned char flags; + unsigned char system_id[32]; + unsigned char volume_id[32]; + unsigned char unused[8]; + unsigned char space_size[8]; + unsigned char escape_sequences[8]; +}; + +/* Common gfs/gfs2 constants: */ +#define GFS_MAGIC 0x01161970 +#define GFS_DEFAULT_BSIZE 4096 +#define GFS_SUPERBLOCK_OFFSET (0x10 * GFS_DEFAULT_BSIZE) +#define GFS_METATYPE_SB 1 +#define GFS_FORMAT_SB 100 +#define GFS_LOCKNAME_LEN 64 + +/* gfs1 constants: */ +#define GFS_FORMAT_FS 1309 +#define GFS_FORMAT_MULTI 1401 +/* gfs2 constants: */ +#define GFS2_FORMAT_FS 1801 +#define GFS2_FORMAT_MULTI 1900 + +struct gfs2_meta_header { + __u32 mh_magic; + __u32 mh_type; + __u64 __pad0; /* Was generation number in gfs1 */ + __u32 mh_format; + __u32 __pad1; /* Was incarnation number in gfs1 */ +}; + +struct gfs2_inum { + __u64 no_formal_ino; + __u64 no_addr; +}; + +struct gfs2_sb { + struct gfs2_meta_header sb_header; + + __u32 sb_fs_format; + __u32 sb_multihost_format; + __u32 __pad0; /* Was superblock flags in gfs1 */ + + __u32 sb_bsize; + __u32 sb_bsize_shift; + __u32 __pad1; /* Was journal segment size in gfs1 */ + + struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */ + struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */ + struct gfs2_inum sb_root_dir; + + char sb_lockproto[GFS_LOCKNAME_LEN]; + char sb_locktable[GFS_LOCKNAME_LEN]; + /* In gfs1, quota and license dinodes followed */ +}; + +struct ntfs_super_block { + __u8 jump[3]; + __u8 oem_id[8]; + __u8 bios_parameter_block[25]; + __u16 unused[2]; + __u64 number_of_sectors; + __u64 mft_cluster_location; + __u64 mft_mirror_cluster_location; + __s8 cluster_per_mft_record; + __u8 reserved1[3]; + __s8 cluster_per_index_record; + __u8 reserved2[3]; + __u64 volume_serial; + __u16 checksum; +}; + +struct master_file_table_record { + __u32 magic; + __u16 usa_ofs; + __u16 usa_count; + __u64 lsn; + __u16 sequence_number; + __u16 link_count; + __u16 attrs_offset; + __u16 flags; + __u32 bytes_in_use; + __u32 bytes_allocated; +} __attribute__((__packed__)); + +struct file_attribute { + __u32 type; + __u32 len; + __u8 non_resident; + __u8 name_len; + __u16 name_offset; + __u16 flags; + __u16 instance; + __u32 value_len; + __u16 value_offset; +} __attribute__((__packed__)); + +#define MFT_RECORD_VOLUME 3 +#define MFT_RECORD_ATTR_VOLUME_NAME 0x60 +#define MFT_RECORD_ATTR_VOLUME_INFO 0x70 +#define MFT_RECORD_ATTR_OBJECT_ID 0x40 +#define MFT_RECORD_ATTR_END 0xffffffffu + +/* HFS / HFS+ */ +struct hfs_finder_info { + __u32 boot_folder; + __u32 start_app; + __u32 open_folder; + __u32 os9_folder; + __u32 reserved; + __u32 osx_folder; + __u8 id[8]; +} __attribute__((packed)); + +struct hfs_mdb { + __u8 signature[2]; + __u32 cr_date; + __u32 ls_Mod; + __u16 atrb; + __u16 nm_fls; + __u16 vbm_st; + __u16 alloc_ptr; + __u16 nm_al_blks; + __u32 al_blk_size; + __u32 clp_size; + __u16 al_bl_st; + __u32 nxt_cnid; + __u16 free_bks; + __u8 label_len; + __u8 label[27]; + __u32 vol_bkup; + __u16 vol_seq_num; + __u32 wr_cnt; + __u32 xt_clump_size; + __u32 ct_clump_size; + __u16 num_root_dirs; + __u32 file_count; + __u32 dir_count; + struct hfs_finder_info finder_info; + __u8 embed_sig[2]; + __u16 embed_startblock; + __u16 embed_blockcount; +} __attribute__((packed)); + + +#define HFS_NODE_LEAF 0xff +#define HFSPLUS_POR_CNID 1 + +struct hfsplus_bnode_descriptor { + __u32 next; + __u32 prev; + __u8 type; + __u8 height; + __u16 num_recs; + __u16 reserved; +} __attribute__((packed)); + +struct hfsplus_bheader_record { + __u16 depth; + __u32 root; + __u32 leaf_count; + __u32 leaf_head; + __u32 leaf_tail; + __u16 node_size; +} __attribute__((packed)); + +struct hfsplus_catalog_key { + __u16 key_len; + __u32 parent_id; + __u16 unicode_len; + __u8 unicode[255 * 2]; +} __attribute__((packed)); + +struct hfsplus_extent { + __u32 start_block; + __u32 block_count; +} __attribute__((packed)); + +#define HFSPLUS_EXTENT_COUNT 8 +struct hfsplus_fork { + __u64 total_size; + __u32 clump_size; + __u32 total_blocks; + struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; +} __attribute__((packed)); + +struct hfsplus_vol_header { + __u8 signature[2]; + __u16 version; + __u32 attributes; + __u32 last_mount_vers; + __u32 reserved; + __u32 create_date; + __u32 modify_date; + __u32 backup_date; + __u32 checked_date; + __u32 file_count; + __u32 folder_count; + __u32 blocksize; + __u32 total_blocks; + __u32 free_blocks; + __u32 next_alloc; + __u32 rsrc_clump_sz; + __u32 data_clump_sz; + __u32 next_cnid; + __u32 write_count; + __u64 encodings_bmp; + struct hfs_finder_info finder_info; + struct hfsplus_fork alloc_file; + struct hfsplus_fork ext_file; + struct hfsplus_fork cat_file; + struct hfsplus_fork attr_file; + struct hfsplus_fork start_file; +} __attribute__((packed)); + + +/* this is lvm's label_header & pv_header combined. */ + +#define LVM2_ID_LEN 32 + +struct lvm2_pv_label_header { + /* label_header */ + __u8 id[8]; /* LABELONE */ + __u64 sector_xl; /* Sector number of this label */ + __u32 crc_xl; /* From next field to end of sector */ + __u32 offset_xl; /* Offset from start of struct to contents */ + __u8 type[8]; /* LVM2 001 */ + /* pv_header */ + __u8 pv_uuid[LVM2_ID_LEN]; +} __attribute__ ((packed)); + + +/* + * 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 +#define BTRFS_UUID_SIZE 16 +#define BTRFS_FSID_SIZE 16 +#define BTRFS_CSUM_SIZE 32 + +struct btrfs_dev_item { + /* 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; + + /* expected generation for this device */ + __u64 generation; + + /* + * starting byte of this partition on the device, + * to allow for stripe alignment in the future + */ + __u64 start_offset; + + /* grouping information for allocation decisions */ + __u32 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__)); + +/* + * 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 */ + __u64 bytenr; /* this block number */ + __u64 flags; + + /* allowed to be different from the btrfs_header from here own down */ + __u64 magic; + __u64 generation; + __u64 root; + __u64 chunk_root; + __u64 log_root; + + /* this will help find the new super based on the log root */ + __u64 log_root_transid; + __u64 total_bytes; + __u64 bytes_used; + __u64 root_dir_objectid; + __u64 num_devices; + __u32 sectorsize; + __u32 nodesize; + __u32 leafsize; + __u32 stripesize; + __u32 sys_chunk_array_size; + __u64 chunk_root_generation; + __u64 compat_flags; + __u64 compat_ro_flags; + __u64 incompat_flags; + __u16 csum_type; + __u8 root_level; + __u8 chunk_root_level; + __u8 log_root_level; + struct btrfs_dev_item dev_item; + + char label[BTRFS_LABEL_SIZE]; + + /* future expansion */ + __u64 reserved[32]; + __u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; +} __attribute__ ((__packed__)); + +#define F2FS_MAX_EXTENSION 64 /* # of extension entries */ + +struct f2fs_super_block { + __u32 magic; /* Magic Number */ + __u16 major_ver; /* Major Version */ + __u16 minor_ver; /* Minor Version */ + __u32 log_sectorsize; /* log2 sector size in bytes */ + __u32 log_sectors_per_block; /* log2 # of sectors per block */ + __u32 log_blocksize; /* log2 block size in bytes */ + __u32 log_blocks_per_seg; /* log2 # of blocks per segment */ + __u32 segs_per_sec; /* # of segments per section */ + __u32 secs_per_zone; /* # of sections per zone */ + __u32 checksum_offset; /* checksum offset inside super block */ + __u64 block_count; /* total # of user blocks */ + __u32 section_count; /* total # of sections */ + __u32 segment_count; /* total # of segments */ + __u32 segment_count_ckpt; /* # of segments for checkpoint */ + __u32 segment_count_sit; /* # of segments for SIT */ + __u32 segment_count_nat; /* # of segments for NAT */ + __u32 segment_count_ssa; /* # of segments for SSA */ + __u32 segment_count_main; /* # of segments for main area */ + __u32 segment0_blkaddr; /* start block address of segment 0 */ + __u32 cp_blkaddr; /* start block address of checkpoint */ + __u32 sit_blkaddr; /* start block address of SIT */ + __u32 nat_blkaddr; /* start block address of NAT */ + __u32 ssa_blkaddr; /* start block address of SSA */ + __u32 main_blkaddr; /* start block address of main area */ + __u32 root_ino; /* root inode number */ + __u32 node_ino; /* node inode number */ + __u32 meta_ino; /* meta inode number */ + __u8 uuid[16]; /* 128-bit uuid for volume */ + __u16 volume_name[512]; /* volume name */ + __u32 extension_count; /* # of extensions below */ + __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */ +} __attribute__((__packed__)); + +struct exfat_super_block { + uint8_t jump[3]; + uint8_t oem_name[8]; + uint8_t __unused1[53]; + uint64_t block_start; + uint64_t block_count; + uint32_t fat_block_start; + uint32_t fat_block_count; + uint32_t cluster_block_start; + uint32_t cluster_count; + uint32_t rootdir_cluster; + uint8_t volume_serial[4]; + struct { + uint8_t vermin; + uint8_t vermaj; + } version; + uint16_t volume_state; + uint8_t block_bits; + uint8_t bpc_bits; + uint8_t fat_count; + uint8_t drive_no; + uint8_t allocated_percent; +} __attribute__((__packed__)); + +struct exfat_entry_label { + uint8_t type; + uint8_t length; + uint8_t name[30]; +} __attribute__((__packed__)); + +#define BLOCK_SIZE(sb) (1 << (sb)->block_bits) +#define CLUSTER_SIZE(sb) (BLOCK_SIZE(sb) << (sb)->bpc_bits) + +#define EXFAT_FIRST_DATA_CLUSTER 2 +#define EXFAT_LAST_DATA_CLUSTER 0xffffff6 +#define EXFAT_ENTRY_SIZE 32 + +#define EXFAT_ENTRY_EOD 0x00 +#define EXFAT_ENTRY_LABEL 0x83 + +/* + * Byte swap functions + */ +#ifdef __GNUC__ +#define _INLINE_ static __inline__ +#else /* For Watcom C */ +#define _INLINE_ static inline +#endif + +static __u16 blkid_swab16(__u16 val); +static __u32 blkid_swab32(__u32 val); +static __u64 blkid_swab64(__u64 val); + +#if ((defined __GNUC__) && \ + (defined(__i386__) || defined(__i486__) || defined(__i586__))) + +#define _BLKID_HAVE_ASM_BITOPS_ + +_INLINE_ __u32 blkid_swab32(__u32 val) +{ +#ifdef EXT2FS_REQUIRE_486 + __asm__("bswap %0" : "=r" (val) : "0" (val)); +#else + __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ + "rorl $16,%0\n\t" /* swap words */ + "xchgb %b0,%h0" /* swap higher bytes */ + :"=q" (val) + : "0" (val)); +#endif + return val; +} + +_INLINE_ __u16 blkid_swab16(__u16 val) +{ + __asm__("xchgb %b0,%h0" /* swap bytes */ \ + : "=q" (val) \ + : "0" (val)); \ + return val; +} + +_INLINE_ __u64 blkid_swab64(__u64 val) +{ + return (blkid_swab32(val >> 32) | + (((__u64) blkid_swab32(val & 0xFFFFFFFFUL)) << 32)); +} +#endif + +#if !defined(_BLKID_HAVE_ASM_BITOPS_) + +_INLINE_ __u16 blkid_swab16(__u16 val) +{ + return (val >> 8) | (val << 8); +} + +_INLINE_ __u32 blkid_swab32(__u32 val) +{ + return ((val>>24) | ((val>>8)&0xFF00) | + ((val<<8)&0xFF0000) | (val<<24)); +} + +_INLINE_ __u64 blkid_swab64(__u64 val) +{ + return (blkid_swab32(val >> 32) | + (((__u64) blkid_swab32(val & 0xFFFFFFFFUL)) << 32)); +} +#endif + + + +#ifdef WORDS_BIGENDIAN +#define blkid_le16(x) blkid_swab16(x) +#define blkid_le32(x) blkid_swab32(x) +#define blkid_le64(x) blkid_swab64(x) +#define blkid_be16(x) (x) +#define blkid_be32(x) (x) +#define blkid_be64(x) (x) +#else +#define blkid_le16(x) (x) +#define blkid_le32(x) (x) +#define blkid_le64(x) (x) +#define blkid_be16(x) blkid_swab16(x) +#define blkid_be32(x) blkid_swab32(x) +#define blkid_be64(x) blkid_swab64(x) +#endif + +#undef _INLINE_ + +#endif /* _BLKID_PROBE_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/read.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/read.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,494 @@ +/* + * read.c - read the blkid cache from disk, to avoid scanning all devices + * + * Copyright (C) 2001, 2003 Theodore Y. Ts'o + * Copyright (C) 2001 Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#define _XOPEN_SOURCE 600 /* for inclusion of strtoull */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#if HAVE_ERRNO_H +#include +#endif + +#include "blkidP.h" +#include "uuid/uuid.h" + +#ifdef HAVE_STRTOULL +#define STRTOULL strtoull /* defined in stdlib.h if you try hard enough */ +#else +/* FIXME: need to support real strtoull here */ +#define STRTOULL strtoul +#endif + +#if HAVE_STDLIB_H +#include +#endif + +#ifdef TEST_PROGRAM +#define blkid_debug_dump_dev(dev) (debug_dump_dev(dev)) +static void debug_dump_dev(blkid_dev dev); +#endif + +/* + * File format: + * + * ...]>device_name + * + * The following tags are required for each entry: + * unique (within this file) ID number of this device + * (ascii time_t) time this entry was last read from disk + * (detected) type of filesystem/data for this partition + * + * The following tags may be present, depending on the device contents + * (user supplied) label (volume name, etc) + * (generated) universally unique identifier (serial no) + */ + +static char *skip_over_blank(char *cp) +{ + while (*cp && isspace(*cp)) + cp++; + return cp; +} + +static char *skip_over_word(char *cp) +{ + char ch; + + while ((ch = *cp)) { + /* If we see a backslash, skip the next character */ + if (ch == '\\') { + cp++; + if (*cp == '\0') + break; + cp++; + continue; + } + if (isspace(ch) || ch == '<' || ch == '>') + break; + cp++; + } + return cp; +} + +static char *strip_line(char *line) +{ + char *p; + + line = skip_over_blank(line); + + p = line + strlen(line) - 1; + + while (*line) { + if (isspace(*p)) + *p-- = '\0'; + else + break; + } + + return line; +} + +#if 0 +static char *parse_word(char **buf) +{ + char *word, *next; + + word = *buf; + if (*word == '\0') + return NULL; + + word = skip_over_blank(word); + next = skip_over_word(word); + if (*next) { + char *end = next - 1; + if (*end == '"' || *end == '\'') + *end = '\0'; + *next++ = '\0'; + } + *buf = next; + + if (*word == '"' || *word == '\'') + word++; + return word; +} +#endif + +/* + * Start parsing a new line from the cache. + * + * line starts with " continue parsing line + * line starts with " skip line + * line starts with other, return -BLKID_ERR_CACHE -> error + */ +static int parse_start(char **cp) +{ + char *p; + + p = strip_line(*cp); + + /* Skip comment or blank lines. We can't just NUL the first '#' char, + * in case it is inside quotes, or escaped. + */ + if (*p == '\0' || *p == '#') + return 0; + + if (!strncmp(p, "", 9)) { + DBG(DEBUG_READ, printf("found device trailer %9s\n", *cp)); + *cp += 9; + return 0; + } + + return -BLKID_ERR_CACHE; +} + +/* + * Allocate a new device struct with device name filled in. Will handle + * finding the device on lines of the form: + * devname + * devnamebar + */ +static int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp) +{ + char *start, *tmp, *end, *name; + int ret; + + if ((ret = parse_start(cp)) <= 0) + return ret; + + start = tmp = strchr(*cp, '>'); + if (!start) { + DBG(DEBUG_READ, + printf("blkid: short line parsing dev: %s\n", *cp)); + return -BLKID_ERR_CACHE; + } + start = skip_over_blank(start + 1); + end = skip_over_word(start); + + DBG(DEBUG_READ, printf("device should be %.*s\n", + (int)(end - start), start)); + + if (**cp == '>') + *cp = end; + else + (*cp)++; + + *tmp = '\0'; + + if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) { + DBG(DEBUG_READ, + printf("blkid: missing ending: %s\n", end)); + } else if (tmp) + *tmp = '\0'; + + if (end - start <= 1) { + DBG(DEBUG_READ, printf("blkid: empty device name: %s\n", *cp)); + return -BLKID_ERR_CACHE; + } + + name = blkid_strndup(start, end-start); + if (name == NULL) + return -BLKID_ERR_MEM; + + DBG(DEBUG_READ, printf("found dev %s\n", name)); + + if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE))) { + free(name); + return -BLKID_ERR_MEM; + } + + free(name); + return 1; +} + +/* + * Extract a tag of the form NAME="value" from the line. + */ +static int parse_token(char **name, char **value, char **cp) +{ + char *end; + + if (!name || !value || !cp) + return -BLKID_ERR_PARAM; + + if (!(*value = strchr(*cp, '='))) + return 0; + + **value = '\0'; + *name = strip_line(*cp); + *value = skip_over_blank(*value + 1); + + if (**value == '"') { + end = strchr(*value + 1, '"'); + if (!end) { + DBG(DEBUG_READ, + printf("unbalanced quotes at: %s\n", *value)); + *cp = *value; + return -BLKID_ERR_CACHE; + } + (*value)++; + *end = '\0'; + end++; + } else { + end = skip_over_word(*value); + if (*end) { + *end = '\0'; + end++; + } + } + *cp = end; + + return 1; +} + +/* + * Extract a tag of the form value from the line. + */ +/* +static int parse_xml(char **name, char **value, char **cp) +{ + char *end; + + if (!name || !value || !cp) + return -BLKID_ERR_PARAM; + + *name = strip_line(*cp); + + if ((*name)[0] != '<' || (*name)[1] == '/') + return 0; + + FIXME: finish this. +} +*/ + +/* + * Extract a tag from the line. + * + * Return 1 if a valid tag was found. + * Return 0 if no tag found. + * Return -ve error code. + */ +static int parse_tag(blkid_cache cache, blkid_dev dev, char **cp) +{ + char *name; + char *value; + int ret; + + if (!cache || !dev) + return -BLKID_ERR_PARAM; + + if ((ret = parse_token(&name, &value, cp)) <= 0 /* && + (ret = parse_xml(&name, &value, cp)) <= 0 */) + return ret; + + /* Some tags are stored directly in the device struct */ + if (!strcmp(name, "DEVNO")) + dev->bid_devno = STRTOULL(value, 0, 0); + else if (!strcmp(name, "PRI")) + dev->bid_pri = strtol(value, 0, 0); + else if (!strcmp(name, "TIME")) + dev->bid_time = STRTOULL(value, 0, 0); + else + ret = blkid_set_tag(dev, name, value, strlen(value)); + + DBG(DEBUG_READ, printf(" tag: %s=\"%s\"\n", name, value)); + + return ret < 0 ? ret : 1; +} + +/* + * Parse a single line of data, and return a newly allocated dev struct. + * Add the new device to the cache struct, if one was read. + * + * Lines are of the form /dev/foo + * + * Returns -ve value on error. + * Returns 0 otherwise. + * If a valid device was read, *dev_p is non-NULL, otherwise it is NULL + * (e.g. comment lines, unknown XML content, etc). + */ +static int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp) +{ + blkid_dev dev; + int ret; + + if (!cache || !dev_p) + return -BLKID_ERR_PARAM; + + *dev_p = NULL; + + DBG(DEBUG_READ, printf("line: %s\n", cp)); + + if ((ret = parse_dev(cache, dev_p, &cp)) <= 0) + return ret; + + dev = *dev_p; + + while ((ret = parse_tag(cache, dev, &cp)) > 0) { + ; + } + + if (dev->bid_type == NULL) { + DBG(DEBUG_READ, + printf("blkid: device %s has no TYPE\n",dev->bid_name)); + blkid_free_dev(dev); + } + + DBG(DEBUG_READ, blkid_debug_dump_dev(dev)); + + return ret; +} + +/* + * Parse the specified filename, and return the data in the supplied or + * a newly allocated cache struct. If the file doesn't exist, return a + * new empty cache struct. + */ +void blkid_read_cache(blkid_cache cache) +{ + FILE *file; + char buf[4096]; + int fd, lineno = 0; + struct stat st; + + if (!cache) + return; + + /* + * If the file doesn't exist, then we just return an empty + * struct so that the cache can be populated. + */ + if ((fd = open(cache->bic_filename, O_RDONLY)) < 0) + return; + if (fstat(fd, &st) < 0) + goto errout; + if ((st.st_mtime == cache->bic_ftime) || + (cache->bic_flags & BLKID_BIC_FL_CHANGED)) { + DBG(DEBUG_CACHE, printf("skipping re-read of %s\n", + cache->bic_filename)); + goto errout; + } + + DBG(DEBUG_CACHE, printf("reading cache file %s\n", + cache->bic_filename)); + + file = fdopen(fd, "r"); + if (!file) + goto errout; + + while (fgets(buf, sizeof(buf), file)) { + blkid_dev dev; + unsigned int end; + + lineno++; + if (buf[0] == 0) + continue; + end = strlen(buf) - 1; + /* Continue reading next line if it ends with a backslash */ + while (buf[end] == '\\' && end < sizeof(buf) - 2 && + fgets(buf + end, sizeof(buf) - end, file)) { + end = strlen(buf) - 1; + lineno++; + } + + if (blkid_parse_line(cache, &dev, buf) < 0) { + DBG(DEBUG_READ, + printf("blkid: bad format on line %d\n", lineno)); + continue; + } + } + fclose(file); + + /* + * Initially we do not need to write out the cache file. + */ + cache->bic_flags &= ~BLKID_BIC_FL_CHANGED; + cache->bic_ftime = st.st_mtime; + + return; +errout: + close(fd); + return; +} + +#ifdef TEST_PROGRAM +static void debug_dump_dev(blkid_dev dev) +{ + struct list_head *p; + + if (!dev) { + printf(" dev: NULL\n"); + return; + } + + printf(" dev: name = %s\n", dev->bid_name); + printf(" dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno); + printf(" dev: TIME=\"%lld\"\n", (long long)dev->bid_time); + printf(" dev: PRI=\"%d\"\n", dev->bid_pri); + printf(" dev: flags = 0x%08X\n", dev->bid_flags); + + list_for_each(p, &dev->bid_tags) { + blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); + if (tag) + printf(" tag: %s=\"%s\"\n", tag->bit_name, + tag->bit_val); + else + printf(" tag: NULL\n"); + } + printf("\n"); +} + +int main(int argc, char**argv) +{ + blkid_cache cache = NULL; + int ret; + + blkid_debug_mask = DEBUG_ALL; + if (argc > 2) { + fprintf(stderr, "Usage: %s [filename]\n" + "Test parsing of the cache (filename)\n", argv[0]); + exit(1); + } + if ((ret = blkid_get_cache(&cache, argv[1])) < 0) + fprintf(stderr, "error %d reading cache file %s\n", ret, + argv[1] ? argv[1] : BLKID_CACHE_FILE); + + blkid_put_cache(cache); + + return ret; +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/resolve.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/resolve.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,140 @@ +/* + * resolve.c - resolve names and tags into specific devices + * + * Copyright (C) 2001, 2003 Theodore Ts'o. + * Copyright (C) 2001 Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include +#include +#include "blkidP.h" + +/* + * Find a tagname (e.g. LABEL or UUID) on a specific device. + */ +char *blkid_get_tag_value(blkid_cache cache, const char *tagname, + const char *devname) +{ + blkid_tag found; + blkid_dev dev; + blkid_cache c = cache; + char *ret = NULL; + + DBG(DEBUG_RESOLVE, printf("looking for %s on %s\n", tagname, devname)); + + if (!devname) + return NULL; + + if (!cache) { + if (blkid_get_cache(&c, NULL) < 0) + return NULL; + } + + if ((dev = blkid_get_dev(c, devname, BLKID_DEV_NORMAL)) && + (found = blkid_find_tag_dev(dev, tagname))) + ret = blkid_strdup(found->bit_val); + + if (!cache) + blkid_put_cache(c); + + return ret; +} + +/* + * Locate a device name from a token (NAME=value string), or (name, value) + * pair. In the case of a token, value is ignored. If the "token" is not + * of the form "NAME=value" and there is no value given, then it is assumed + * to be the actual devname and a copy is returned. + */ +char *blkid_get_devname(blkid_cache cache, const char *token, + const char *value) +{ + blkid_dev dev; + blkid_cache c = cache; + char *t = 0, *v = 0; + char *ret = NULL; + + if (!token) + return NULL; + + if (!cache) { + if (blkid_get_cache(&c, NULL) < 0) + return NULL; + } + + DBG(DEBUG_RESOLVE, + printf("looking for %s%s%s %s\n", token, value ? "=" : "", + value ? value : "", cache ? "in cache" : "from disk")); + + if (!value) { + if (!strchr(token, '=')) { + ret = blkid_strdup(token); + goto out; + } + blkid_parse_tag_string(token, &t, &v); + if (!t || !v) + goto out; + token = t; + value = v; + } + + dev = blkid_find_dev_with_tag(c, token, value); + if (!dev) + goto out; + + ret = blkid_strdup(blkid_dev_devname(dev)); + +out: + free(t); + free(v); + if (!cache) { + blkid_put_cache(c); + } + return (ret); +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + char *value; + blkid_cache cache; + + blkid_debug_mask = DEBUG_ALL; + if (argc != 2 && argc != 3) { + fprintf(stderr, "Usage:\t%s tagname=value\n" + "\t%s tagname devname\n" + "Find which device holds a given token or\n" + "Find what the value of a tag is in a device\n", + argv[0], argv[0]); + exit(1); + } + if (blkid_get_cache(&cache, "/dev/null") < 0) { + fprintf(stderr, "Couldn't get blkid cache\n"); + exit(1); + } + + if (argv[2]) { + value = blkid_get_tag_value(cache, argv[1], argv[2]); + printf("%s has tag %s=%s\n", argv[2], argv[1], + value ? value : ""); + } else { + value = blkid_get_devname(cache, argv[1], NULL); + printf("%s has tag %s\n", value ? value : "", argv[1]); + } + blkid_put_cache(cache); + return value ? 0 : 1; +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/save.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/save.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,205 @@ +/* + * save.c - write the cache struct to disk + * + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_MKDEV_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#include "blkidP.h" + +#ifdef _WIN32 +#include "windows.h" +#endif + +static int save_dev(blkid_dev dev, FILE *file) +{ + struct list_head *p; + + if (!dev || dev->bid_name[0] != '/') + return 0; + + DBG(DEBUG_SAVE, + printf("device %s, type %s\n", dev->bid_name, dev->bid_type ? + dev->bid_type : "(null)")); + + fprintf(file, + "bid_devno, (long) dev->bid_time); + if (dev->bid_pri) + fprintf(file, " PRI=\"%d\"", dev->bid_pri); + list_for_each(p, &dev->bid_tags) { + blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); + fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val); + } + fprintf(file, ">%s\n", dev->bid_name); + + return 0; +} + +/* + * Write out the cache struct to the cache file on disk. + */ +int blkid_flush_cache(blkid_cache cache) +{ + struct list_head *p; + char *tmp = NULL; + const char *opened = NULL; + const char *filename; + FILE *file = NULL; + int fd, ret = 0; + struct stat st; + + if (!cache) + return -BLKID_ERR_PARAM; + + if (list_empty(&cache->bic_devs) || + !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) { + DBG(DEBUG_SAVE, printf("skipping cache file write\n")); + return 0; + } + + filename = cache->bic_filename ? cache->bic_filename: BLKID_CACHE_FILE; + + /* If we can't write to the cache file, then don't even try */ + if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) || + (ret == 0 && access(filename, W_OK) < 0)) { + DBG(DEBUG_SAVE, + printf("can't write to cache file %s\n", filename)); + return 0; + } + + /* + * Try and create a temporary file in the same directory so + * that in case of error we don't overwrite the cache file. + * If the cache file doesn't yet exist, it isn't a regular + * file (e.g. /dev/null or a socket), or we couldn't create + * a temporary file then we open it directly. + */ + if (ret == 0 && S_ISREG(st.st_mode)) { + tmp = malloc(strlen(filename) + 8); + if (tmp) { + mode_t save_umask = umask(022); + sprintf(tmp, "%s-XXXXXX", filename); + fd = mkstemp(tmp); + umask(save_umask); + if (fd >= 0) { + file = fdopen(fd, "w"); + opened = tmp; + } +#ifndef _WIN32 + fchmod(fd, 0644); +#else + chmod(tmp, 0644); +#endif + } + } + + if (!file) { + file = fopen(filename, "w"); + opened = filename; + } + + DBG(DEBUG_SAVE, + printf("writing cache file %s (really %s)\n", + filename, opened)); + + if (!file) { + ret = errno; + goto errout; + } + + list_for_each(p, &cache->bic_devs) { + blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); + if (!dev->bid_type) + continue; + if ((ret = save_dev(dev, file)) < 0) + break; + } + + if (ret >= 0) { + cache->bic_flags &= ~BLKID_BIC_FL_CHANGED; + ret = 1; + } + + fclose(file); + if (opened != filename) { + if (ret < 0) { + (void) unlink(opened); + DBG(DEBUG_SAVE, + printf("unlinked temp cache %s\n", opened)); + } else { + char *backup; + + backup = malloc(strlen(filename) + 5); + if (backup) { + sprintf(backup, "%s.old", filename); + unlink(backup); + (void) link(filename, backup); + free(backup); + } + if (rename(opened, filename) < 0) + (void) unlink(opened); + DBG(DEBUG_SAVE, + printf("moved temp cache %s\n", opened)); + } + } + +errout: + free(tmp); + return ret; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + blkid_cache cache = NULL; + int ret; + + blkid_debug_mask = DEBUG_ALL; + if (argc > 2) { + fprintf(stderr, "Usage: %s [filename]\n" + "Test loading/saving a cache (filename)\n", argv[0]); + exit(1); + } + + if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + if ((ret = blkid_probe_all(cache)) < 0) { + fprintf(stderr, "error (%d) probing devices\n", ret); + exit(1); + } + cache->bic_filename = blkid_strdup(argv[1]); + + if ((ret = blkid_flush_cache(cache)) < 0) { + fprintf(stderr, "error (%d) saving cache\n", ret); + exit(1); + } + + blkid_put_cache(cache); + + return ret; +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/tag.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/tag.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,471 @@ +/* + * tag.c - allocation/initialization/free routines for tag structs + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include +#include + +#include "blkidP.h" + +static blkid_tag blkid_new_tag(void) +{ + blkid_tag tag; + + if (!(tag = (blkid_tag) calloc(1, sizeof(struct blkid_struct_tag)))) + return NULL; + + INIT_LIST_HEAD(&tag->bit_tags); + INIT_LIST_HEAD(&tag->bit_names); + + return tag; +} + +#ifdef CONFIG_BLKID_DEBUG +void blkid_debug_dump_tag(blkid_tag tag) +{ + if (!tag) { + printf(" tag: NULL\n"); + return; + } + + printf(" tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val); +} +#endif + +void blkid_free_tag(blkid_tag tag) +{ + if (!tag) + return; + + DBG(DEBUG_TAG, printf(" freeing tag %s=%s\n", tag->bit_name, + tag->bit_val ? tag->bit_val : "(NULL)")); + DBG(DEBUG_TAG, blkid_debug_dump_tag(tag)); + + list_del(&tag->bit_tags); /* list of tags for this device */ + list_del(&tag->bit_names); /* list of tags with this type */ + + free(tag->bit_name); + free(tag->bit_val); + + free(tag); +} + +/* + * Find the desired tag on a device. If value is NULL, then the + * first such tag is returned, otherwise return only exact tag if found. + */ +blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type) +{ + struct list_head *p; + + if (!dev || !type) + return NULL; + + list_for_each(p, &dev->bid_tags) { + blkid_tag tmp = list_entry(p, struct blkid_struct_tag, + bit_tags); + + if (!strcmp(tmp->bit_name, type)) + return tmp; + } + return NULL; +} + +extern int blkid_dev_has_tag(blkid_dev dev, const char *type, + const char *value) +{ + blkid_tag tag; + + if (!dev || !type) + return -1; + + tag = blkid_find_tag_dev(dev, type); + if (!value) + return (tag != NULL); + if (!tag || strcmp(tag->bit_val, value)) + return 0; + return 1; +} + +/* + * Find the desired tag type in the cache. + * We return the head tag for this tag type. + */ +static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type) +{ + blkid_tag head = NULL, tmp; + struct list_head *p; + + if (!cache || !type) + return NULL; + + list_for_each(p, &cache->bic_tags) { + tmp = list_entry(p, struct blkid_struct_tag, bit_tags); + if (!strcmp(tmp->bit_name, type)) { + DBG(DEBUG_TAG, + printf(" found cache tag head %s\n", type)); + head = tmp; + break; + } + } + return head; +} + +/* + * Set a tag on an existing device. + * + * If value is NULL, then delete the tagsfrom the device. + */ +int blkid_set_tag(blkid_dev dev, const char *name, + const char *value, const int vlength) +{ + blkid_tag t = 0, head = 0; + char *val = 0; + char **dev_var = 0; + + if (!dev || !name) + return -BLKID_ERR_PARAM; + + if (!(val = blkid_strndup(value, vlength)) && value) + return -BLKID_ERR_MEM; + + /* + * Certain common tags are linked directly to the device struct + * We need to know what they are before we do anything else because + * the function name parameter might get freed later on. + */ + if (!strcmp(name, "TYPE")) + dev_var = &dev->bid_type; + else if (!strcmp(name, "LABEL")) + dev_var = &dev->bid_label; + else if (!strcmp(name, "UUID")) + dev_var = &dev->bid_uuid; + + t = blkid_find_tag_dev(dev, name); + if (!value) { + if (t) + blkid_free_tag(t); + } else if (t) { + if (!strcmp(t->bit_val, val)) { + /* Same thing, exit */ + free(val); + return 0; + } + free(t->bit_val); + t->bit_val = val; + } else { + /* Existing tag not present, add to device */ + if (!(t = blkid_new_tag())) + goto errout; + t->bit_name = blkid_strdup(name); + t->bit_val = val; + t->bit_dev = dev; + + list_add_tail(&t->bit_tags, &dev->bid_tags); + + if (dev->bid_cache) { + head = blkid_find_head_cache(dev->bid_cache, + t->bit_name); + if (!head) { + head = blkid_new_tag(); + if (!head) + goto errout; + + DBG(DEBUG_TAG, + printf(" creating new cache tag head %s\n", name)); + head->bit_name = blkid_strdup(name); + if (!head->bit_name) + goto errout; + list_add_tail(&head->bit_tags, + &dev->bid_cache->bic_tags); + } + list_add_tail(&t->bit_names, &head->bit_names); + } + } + + /* Link common tags directly to the device struct */ + if (dev_var) + *dev_var = val; + + if (dev->bid_cache) + dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED; + return 0; + +errout: + if (t) + blkid_free_tag(t); + else free(val); + if (head) + blkid_free_tag(head); + return -BLKID_ERR_MEM; +} + + +/* + * Parse a "NAME=value" string. This is slightly different than + * parse_token, because that will end an unquoted value at a space, while + * this will assume that an unquoted value is the rest of the token (e.g. + * if we are passed an already quoted string from the command-line we don't + * have to both quote and escape quote so that the quotes make it to + * us). + * + * Returns 0 on success, and -1 on failure. + */ +int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val) +{ + char *name, *value, *cp; + + DBG(DEBUG_TAG, printf("trying to parse '%s' as a tag\n", token)); + + if (!token || !(cp = strchr(token, '='))) + return -1; + + name = blkid_strdup(token); + if (!name) + return -1; + value = name + (cp - token); + *value++ = '\0'; + if (*value == '"' || *value == '\'') { + char c = *value++; + if (!(cp = strrchr(value, c))) + goto errout; /* missing closing quote */ + *cp = '\0'; + } + value = blkid_strdup(value); + if (!value) + goto errout; + + *ret_type = name; + *ret_val = value; + + return 0; + +errout: + free(name); + return -1; +} + +/* + * Tag iteration routines for the public libblkid interface. + * + * These routines do not expose the list.h implementation, which are a + * contamination of the namespace, and which force us to reveal far, far + * too much of our internal implementation. I'm not convinced I want + * to keep list.h in the long term, anyway. It's fine for kernel + * programming, but performance is not the #1 priority for this + * library, and I really don't like the tradeoff of type-safety for + * performance for this application. [tytso:20030125.2007EST] + */ + +/* + * This series of functions iterate over all tags in a device + */ +#define TAG_ITERATE_MAGIC 0x01a5284c + +struct blkid_struct_tag_iterate { + int magic; + blkid_dev dev; + struct list_head *p; +}; + +extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev) +{ + blkid_tag_iterate iter; + + iter = malloc(sizeof(struct blkid_struct_tag_iterate)); + if (iter) { + iter->magic = TAG_ITERATE_MAGIC; + iter->dev = dev; + iter->p = dev->bid_tags.next; + } + return (iter); +} + +/* + * Return 0 on success, -1 on error + */ +extern int blkid_tag_next(blkid_tag_iterate iter, + const char **type, const char **value) +{ + blkid_tag tag; + + *type = 0; + *value = 0; + if (!iter || iter->magic != TAG_ITERATE_MAGIC || + iter->p == &iter->dev->bid_tags) + return -1; + tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags); + *type = tag->bit_name; + *value = tag->bit_val; + iter->p = iter->p->next; + return 0; +} + +extern void blkid_tag_iterate_end(blkid_tag_iterate iter) +{ + if (!iter || iter->magic != TAG_ITERATE_MAGIC) + return; + iter->magic = 0; + free(iter); +} + +/* + * This function returns a device which matches a particular + * type/value pair. If there is more than one device that matches the + * search specification, it returns the one with the highest priority + * value. This allows us to give preference to EVMS or LVM devices. + */ +extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache, + const char *type, + const char *value) +{ + blkid_tag head; + blkid_dev dev; + int pri; + struct list_head *p; + int probe_new = 0; + + if (!cache || !type || !value) + return NULL; + + blkid_read_cache(cache); + + DBG(DEBUG_TAG, printf("looking for %s=%s in cache\n", type, value)); + +try_again: + pri = -1; + dev = 0; + head = blkid_find_head_cache(cache, type); + + if (head) { + list_for_each(p, &head->bit_names) { + blkid_tag tmp = list_entry(p, struct blkid_struct_tag, + bit_names); + + if (!strcmp(tmp->bit_val, value) && + (tmp->bit_dev->bid_pri > pri) && + !access(tmp->bit_dev->bid_name, F_OK)) { + dev = tmp->bit_dev; + pri = dev->bid_pri; + } + } + } + if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) { + dev = blkid_verify(cache, dev); + if (!dev || (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED))) + goto try_again; + } + + if (!dev && !probe_new) { + if (blkid_probe_all_new(cache) < 0) + return NULL; + probe_new++; + goto try_again; + } + + if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) { + if (blkid_probe_all(cache) < 0) + return NULL; + goto try_again; + } + return dev; +} + +#ifdef TEST_PROGRAM +#ifdef HAVE_GETOPT_H +#include +#else +extern char *optarg; +extern int optind; +#endif + +void usage(char *prog) +{ + fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device " + "[type value]\n", + prog); + fprintf(stderr, "\tList all tags for a device and exit\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + blkid_tag_iterate iter; + blkid_cache cache = NULL; + blkid_dev dev; + int c, ret, found; + int flags = BLKID_DEV_FIND; + char *tmp; + char *file = NULL; + char *devname = NULL; + char *search_type = NULL; + char *search_value = NULL; + const char *type, *value; + + while ((c = getopt (argc, argv, "m:f:")) != EOF) + switch (c) { + case 'f': + file = optarg; + break; + case 'm': + blkid_debug_mask = strtoul (optarg, &tmp, 0); + if (*tmp) { + fprintf(stderr, "Invalid debug mask: %s\n", + optarg); + exit(1); + } + break; + case '?': + usage(argv[0]); + } + if (argc > optind) + devname = argv[optind++]; + if (argc > optind) + search_type = argv[optind++]; + if (argc > optind) + search_value = argv[optind++]; + if (!devname || (argc != optind)) + usage(argv[0]); + + if ((ret = blkid_get_cache(&cache, file)) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + + dev = blkid_get_dev(cache, devname, flags); + if (!dev) { + fprintf(stderr, "%s: Can not find device in blkid cache\n", + devname); + exit(1); + } + if (search_type) { + found = blkid_dev_has_tag(dev, search_type, search_value); + printf("Device %s: (%s, %s) %s\n", blkid_dev_devname(dev), + search_type, search_value ? search_value : "NULL", + found ? "FOUND" : "NOT FOUND"); + return(!found); + } + printf("Device %s...\n", blkid_dev_devname(dev)); + + iter = blkid_tag_iterate_begin(dev); + while (blkid_tag_next(iter, &type, &value) == 0) { + printf("\tTag %s has value %s\n", type, value); + } + blkid_tag_iterate_end(iter); + + blkid_put_cache(cache); + return (0); +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/tst_types.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/tst_types.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,64 @@ +/* + * This testing program makes sure the blkid_types header file + * + * Copyright (C) 2006 by Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "config.h" +#include +#include "blkid/blkid_types.h" + +#include +#include + +int main(int argc, char **argv) +{ + if (sizeof(__u8) != 1) { + printf("Sizeof(__u8) is %d should be 1\n", + (int)sizeof(__u8)); + exit(1); + } + if (sizeof(__s8) != 1) { + printf("Sizeof(_s8) is %d should be 1\n", + (int)sizeof(__s8)); + exit(1); + } + if (sizeof(__u16) != 2) { + printf("Sizeof(__u16) is %d should be 2\n", + (int)sizeof(__u16)); + exit(1); + } + if (sizeof(__s16) != 2) { + printf("Sizeof(__s16) is %d should be 2\n", + (int)sizeof(__s16)); + exit(1); + } + if (sizeof(__u32) != 4) { + printf("Sizeof(__u32) is %d should be 4\n", + (int)sizeof(__u32)); + exit(1); + } + if (sizeof(__s32) != 4) { + printf("Sizeof(__s32) is %d should be 4\n", + (int)sizeof(__s32)); + exit(1); + } + if (sizeof(__u64) != 8) { + printf("Sizeof(__u64) is %d should be 8\n", + (int)sizeof(__u64)); + exit(1); + } + if (sizeof(__s64) != 8) { + printf("Sizeof(__s64) is %d should be 8\n", + (int)sizeof(__s64)); + exit(1); + } + printf("The blkid_types.h types are correct.\n"); + exit(0); +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libblkid/version.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libblkid/version.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,50 @@ +/* + * version.c --- Return the version of the blkid library + * + * Copyright (C) 2004 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include "config.h" +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#include + +#include +#include "version.h" + +static const char *lib_version = E2FSPROGS_VERSION; +static const char *lib_date = E2FSPROGS_DATE; + +int blkid_parse_version_string(const char *ver_string) +{ + const char *cp; + int version = 0; + + for (cp = ver_string; *cp; cp++) { + if (*cp == '.') + continue; + if (!isdigit(*cp)) + break; + version = (version * 10) + (*cp - '0'); + } + return version; +} + +int blkid_get_library_version(const char **ver_string, + const char **date_string) +{ + if (ver_string) + *ver_string = lib_version; + if (date_string) + *date_string = lib_date; + + return blkid_parse_version_string(lib_version); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,26 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../../.. + +TARGET = libe2p.a libe2p.so +PC_FILENAME = libe2p + +SRC_C = \ + feature.c fgetflags.c fsetflags.c fgetversion.c fsetversion.c \ + getflags.c getversion.c hashstr.c iod.c ls.c ljs.c mntopts.c \ + parse_num.c pe.c pf.c ps.c setflags.c setversion.c uuid.c \ + ostype.c percent.c crypto_mode.c fgetproject.c fsetproject.c + +REQUIRES_LIBS = libet libsupport + +PRIVATE_INCDIR += \ + $(PKGDIR)/lib \ + $(PKGDIR)/lib/libext2fs \ + $(PKGDIR)/lib/libsupport \ + $(PKGDIR)/include/libet \ + $(PKGDIR)/include/libe2p $(PKGDIR)/include/libe2p/e2p \ + $(PKGDIR)/include/libext2fs \ + $(PKGDIR)/include/libsupport + +CONTRIB_INCDIR = libe2p + +include $(L4DIR)/mk/lib.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/crypto_mode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/crypto_mode.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,74 @@ +/* + * crypto_mode.c --- convert between encryption modes and strings + * + * Copyright (C) 1999 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include + +#include "e2p.h" + +struct mode { + int num; + const char *string; +}; + +static struct mode mode_list[] = { + { EXT4_ENCRYPTION_MODE_INVALID, "Invalid"}, + { EXT4_ENCRYPTION_MODE_AES_256_XTS, "AES-256-XTS"}, + { EXT4_ENCRYPTION_MODE_AES_256_GCM, "AES-256-GCM"}, + { EXT4_ENCRYPTION_MODE_AES_256_CBC, "AES-256-CBC"}, + { 0, 0 }, +}; + +const char *e2p_encmode2string(int num) +{ + struct mode *p; + static char buf[20]; + + for (p = mode_list; p->string; p++) { + if (num == p->num) + return p->string; + } + sprintf(buf, "ENC_MODE_%d", num); + return buf; +} + +/* + * Returns the hash algorithm, or -1 on error + */ +int e2p_string2encmode(char *string) +{ + struct mode *p; + char *eptr; + int num; + + for (p = mode_list; p->string; p++) { + if (!strcasecmp(string, p->string)) { + return p->num; + } + } + if (strncasecmp(string, "ENC_MODE_", 9)) + return -1; + + if (string[9] == 0) + return -1; + num = strtol(string+9, &eptr, 10); + if (num > 255 || num < 0) + return -1; + if (*eptr) + return -1; + return num; +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/feature.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/feature.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,427 @@ +/* + * feature.c --- convert between features and strings + * + * Copyright (C) 1999 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include +#include +#include + +#include "e2p.h" +#include +#include + +struct feature { + int compat; + unsigned int mask; + const char *string; +}; + +static struct feature feature_list[] = { + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC, + "dir_prealloc" }, + { E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL, + "has_journal" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES, + "imagic_inodes" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR, + "ext_attr" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX, + "dir_index" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE, + "resize_inode" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_LAZY_BG, + "lazy_bg" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXCLUDE_BITMAP, + "snapshot_bitmap" }, + { E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_SPARSE_SUPER2, + "sparse_super2" }, + + { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER, + "sparse_super" }, + { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE, + "large_file" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_HUGE_FILE, + "huge_file" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM, + "uninit_bg" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM, + "uninit_groups" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_DIR_NLINK, + "dir_nlink" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE, + "extra_isize" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_QUOTA, + "quota" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_BIGALLOC, + "bigalloc"}, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM, + "metadata_csum"}, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_REPLICA, + "replica" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_READONLY, + "read-only" }, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_PROJECT, + "project"}, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS, + "shared_blocks"}, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_VERITY, + "verity"}, + + { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION, + "compression" }, + { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE, + "filetype" }, + { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER, + "needs_recovery" }, + { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV, + "journal_dev" }, + { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS, + "extent" }, + { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS, + "extents" }, + { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG, + "meta_bg" }, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_64BIT, + "64bit" }, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP, + "mmp" }, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG, + "flex_bg"}, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_EA_INODE, + "ea_inode"}, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_DIRDATA, + "dirdata"}, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CSUM_SEED, + "metadata_csum_seed"}, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_LARGEDIR, + "large_dir"}, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_INLINE_DATA, + "inline_data"}, + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_ENCRYPT, + "encrypt"}, + { 0, 0, 0 }, +}; + +static struct feature jrnl_feature_list[] = { + { E2P_FEATURE_COMPAT, JFS_FEATURE_COMPAT_CHECKSUM, + "journal_checksum" }, + + { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_REVOKE, + "journal_incompat_revoke" }, + { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_64BIT, + "journal_64bit" }, + { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_ASYNC_COMMIT, + "journal_async_commit" }, + { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_CSUM_V2, + "journal_checksum_v2" }, + { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_CSUM_V3, + "journal_checksum_v3" }, + { 0, 0, 0 }, +}; + +const char *e2p_feature2string(int compat, unsigned int mask) +{ + struct feature *f; + static char buf[20]; + char fchar; + int fnum; + + for (f = feature_list; f->string; f++) { + if ((compat == f->compat) && + (mask == f->mask)) + return f->string; + } + switch (compat) { + case E2P_FEATURE_COMPAT: + fchar = 'C'; + break; + case E2P_FEATURE_INCOMPAT: + fchar = 'I'; + break; + case E2P_FEATURE_RO_INCOMPAT: + fchar = 'R'; + break; + default: + fchar = '?'; + break; + } + for (fnum = 0; mask >>= 1; fnum++); + sprintf(buf, "FEATURE_%c%d", fchar, fnum); + return buf; +} + +int e2p_string2feature(char *string, int *compat_type, unsigned int *mask) +{ + struct feature *f; + char *eptr; + int num; + + for (f = feature_list; f->string; f++) { + if (!strcasecmp(string, f->string)) { + *compat_type = f->compat; + *mask = f->mask; + return 0; + } + } + if (strncasecmp(string, "FEATURE_", 8)) + return 1; + + switch (string[8]) { + case 'c': + case 'C': + *compat_type = E2P_FEATURE_COMPAT; + break; + case 'i': + case 'I': + *compat_type = E2P_FEATURE_INCOMPAT; + break; + case 'r': + case 'R': + *compat_type = E2P_FEATURE_RO_INCOMPAT; + break; + default: + return 1; + } + if (string[9] == 0) + return 1; + num = strtol(string+9, &eptr, 10); + if (num > 31 || num < 0) + return 1; + if (*eptr) + return 1; + *mask = 1 << num; + return 0; +} + +const char *e2p_jrnl_feature2string(int compat, unsigned int mask) +{ + struct feature *f; + static char buf[20]; + char fchar; + int fnum; + + for (f = jrnl_feature_list; f->string; f++) { + if ((compat == f->compat) && + (mask == f->mask)) + return f->string; + } + switch (compat) { + case E2P_FEATURE_COMPAT: + fchar = 'C'; + break; + case E2P_FEATURE_INCOMPAT: + fchar = 'I'; + break; + case E2P_FEATURE_RO_INCOMPAT: + fchar = 'R'; + break; + default: + fchar = '?'; + break; + } + for (fnum = 0; mask >>= 1; fnum++); + sprintf(buf, "FEATURE_%c%d", fchar, fnum); + return buf; +} + +int e2p_jrnl_string2feature(char *string, int *compat_type, unsigned int *mask) +{ + struct feature *f; + char *eptr; + int num; + + for (f = jrnl_feature_list; f->string; f++) { + if (!strcasecmp(string, f->string)) { + *compat_type = f->compat; + *mask = f->mask; + return 0; + } + } + if (strncasecmp(string, "FEATURE_", 8)) + return 1; + + switch (string[8]) { + case 'c': + case 'C': + *compat_type = E2P_FEATURE_COMPAT; + break; + case 'i': + case 'I': + *compat_type = E2P_FEATURE_INCOMPAT; + break; + case 'r': + case 'R': + *compat_type = E2P_FEATURE_RO_INCOMPAT; + break; + default: + return 1; + } + if (string[9] == 0) + return 1; + num = strtol(string+9, &eptr, 10); + if (num > 31 || num < 0) + return 1; + if (*eptr) + return 1; + *mask = 1 << num; + return 0; +} +static char *skip_over_blanks(char *cp) +{ + while (*cp && isspace(*cp)) + cp++; + return cp; +} + +static char *skip_over_word(char *cp) +{ + while (*cp && !isspace(*cp) && *cp != ',') + cp++; + return cp; +} + +/* + * Edit a feature set array as requested by the user. The ok_array, + * if set, allows the application to limit what features the user is + * allowed to set or clear using this function. If clear_ok_array is set, + * then use it tell whether or not it is OK to clear a filesystem feature. + */ +int e2p_edit_feature2(const char *str, __u32 *compat_array, __u32 *ok_array, + __u32 *clear_ok_array, int *type_err, + unsigned int *mask_err) +{ + char *cp, *buf, *next; + int neg; + unsigned int mask; + int compat_type; + int rc = 0; + + if (!clear_ok_array) + clear_ok_array = ok_array; + + if (type_err) + *type_err = 0; + if (mask_err) + *mask_err = 0; + + buf = malloc(strlen(str)+1); + if (!buf) + return 1; + strcpy(buf, str); + for (cp = buf; cp && *cp; cp = next ? next+1 : 0) { + neg = 0; + cp = skip_over_blanks(cp); + next = skip_over_word(cp); + + if (*next == 0) + next = 0; + else + *next = 0; + + if ((strcasecmp(cp, "none") == 0) || + (strcasecmp(cp, "clear") == 0)) { + compat_array[0] = 0; + compat_array[1] = 0; + compat_array[2] = 0; + continue; + } + + switch (*cp) { + case '-': + case '^': + neg++; + /* fallthrough */ + case '+': + cp++; + break; + } + if (e2p_string2feature(cp, &compat_type, &mask)) { + rc = 1; + break; + } + if (neg) { + if (clear_ok_array && + !(clear_ok_array[compat_type] & mask)) { + rc = 1; + if (type_err) + *type_err = (compat_type | + E2P_FEATURE_NEGATE_FLAG); + if (mask_err) + *mask_err = mask; + break; + } + compat_array[compat_type] &= ~mask; + } else { + if (ok_array && !(ok_array[compat_type] & mask)) { + rc = 1; + if (type_err) + *type_err = compat_type; + if (mask_err) + *mask_err = mask; + break; + } + compat_array[compat_type] |= mask; + } + } + free(buf); + return rc; +} + +int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array) +{ + return e2p_edit_feature2(str, compat_array, ok_array, 0, 0, 0); +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + int compat, compat2, i; + unsigned int mask, mask2; + const char *str; + struct feature *f; + + for (i = 0; i < 2; i++) { + if (i == 0) { + f = feature_list; + printf("Feature list:\n"); + } else { + printf("\nJournal feature list:\n"); + f = jrnl_feature_list; + } + for (; f->string; f++) { + if (i == 0) { + e2p_string2feature((char *)f->string, &compat, + &mask); + str = e2p_feature2string(compat, mask); + } else { + e2p_jrnl_string2feature((char *)f->string, + &compat, &mask); + str = e2p_jrnl_feature2string(compat, mask); + } + + printf("\tCompat = %d, Mask = %u, %s\n", + compat, mask, f->string); + if (strcmp(f->string, str)) { + if (e2p_string2feature((char *) str, &compat2, + &mask2) || + (compat2 != compat) || + (mask2 != mask)) { + fprintf(stderr, "Failure!\n"); + exit(1); + } + } + } + } + exit(0); +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/fgetflags.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/fgetflags.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,102 @@ +/* + * fgetflags.c - Get a file flags on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#include "config.h" +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_EXT2_IOCTLS +#include +#include +#endif + +#include "e2p.h" + +#ifdef O_LARGEFILE +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE) +#else +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK) +#endif + +int fgetflags (const char * name, unsigned long * flags) +{ + struct stat buf; +#if HAVE_STAT_FLAGS && !(APPLE_DARWIN && HAVE_EXT2_IOCTLS) + + if (stat (name, &buf) == -1) + return -1; + + *flags = 0; +#ifdef UF_IMMUTABLE + if (buf.st_flags & UF_IMMUTABLE) + *flags |= EXT2_IMMUTABLE_FL; +#endif +#ifdef UF_APPEND + if (buf.st_flags & UF_APPEND) + *flags |= EXT2_APPEND_FL; +#endif +#ifdef UF_NODUMP + if (buf.st_flags & UF_NODUMP) + *flags |= EXT2_NODUMP_FL; +#endif + + return 0; +#else /* !HAVE_STAT_FLAGS || (APPLE_DARWIN && HAVE_EXT2_IOCTLS) */ +#if HAVE_EXT2_IOCTLS + int fd, r, f, save_errno = 0; + + if (!lstat(name, &buf) && + !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) { + goto notsupp; + } +#if !APPLE_DARWIN + fd = open (name, OPEN_FLAGS); + if (fd == -1) + return -1; + r = ioctl (fd, EXT2_IOC_GETFLAGS, &f); + if (r == -1) + save_errno = errno; + *flags = f; + close (fd); + if (save_errno) + errno = save_errno; + return r; +#else /* APPLE_DARWIN */ + f = -1; + save_errno = syscall(SYS_fsctl, name, EXT2_IOC_GETFLAGS, &f, 0); + *flags = f; + return (save_errno); +#endif /* !APPLE_DARWIN */ +notsupp: +#endif /* HAVE_EXT2_IOCTLS */ +#endif + errno = EOPNOTSUPP; + return -1; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/fgetproject.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/fgetproject.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,63 @@ +/* + * fgetproject.c --- get project id + * + * Copyright (C) 1999 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#include "config.h" +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_EXT2_IOCTLS +#include +#include +#include "project.h" +#endif + +#include "e2p.h" + +#ifdef O_LARGEFILE +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE) +#else +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK) +#endif + +int fgetproject(const char *name, unsigned long *project) +{ +#ifndef FS_IOC_FSGETXATTR + errno = EOPNOTSUPP; + return -1; +#else + int fd, r, save_errno = 0; + struct fsxattr fsx; + + fd = open (name, OPEN_FLAGS); + if (fd == -1) + return -1; + r = ioctl (fd, FS_IOC_FSGETXATTR, &fsx); + if (r == 0) + *project = fsx.fsx_projid; + save_errno = errno; + close (fd); + if (save_errno) + errno = save_errno; + return r; +#endif +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/fgetversion.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/fgetversion.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,76 @@ +/* + * fgetversion.c - Get a file version on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#include "config.h" +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#include +#if HAVE_SYS_IOCTL_H +#include +#endif + +#include "e2p.h" + +#ifdef O_LARGEFILE +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE) +#else +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK) +#endif + +int fgetversion(const char *name, unsigned long *version) +{ + unsigned int ver = -1; + int rc = -1; +#if HAVE_EXT2_IOCTLS +# if !APPLE_DARWIN + int fd, save_errno = 0; + + fd = open(name, OPEN_FLAGS); + if (fd == -1) + return -1; + + rc = ioctl(fd, EXT2_IOC_GETVERSION, &ver); + if (rc == -1) + save_errno = errno; + close(fd); + if (rc == -1) + errno = save_errno; +# else /* APPLE_DARWIN */ + rc = syscall(SYS_fsctl, name, EXT2_IOC_GETVERSION, &ver, 0); +# endif /* !APPLE_DARWIN */ +#else /* ! HAVE_EXT2_IOCTLS */ + extern int errno; + + errno = EOPNOTSUPP; +#endif /* ! HAVE_EXT2_IOCTLS */ + if (rc == 0) + *version = ver; + + return rc; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/fsetflags.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/fsetflags.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,107 @@ +/* + * fsetflags.c - Set a file flags on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#include "config.h" +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_EXT2_IOCTLS +#include +#include +#endif + +#include "e2p.h" + +/* + * Deal with lame glibc's that define this function without actually + * implementing it. Can you say "attractive nuisance", boys and girls? + * I knew you could! + */ +#ifdef __linux__ +#undef HAVE_CHFLAGS +#endif + +#ifdef O_LARGEFILE +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE) +#else +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK) +#endif + +int fsetflags (const char * name, unsigned long flags) +{ +#if HAVE_CHFLAGS && !(APPLE_DARWIN && HAVE_EXT2_IOCTLS) + unsigned long bsd_flags = 0; + +#ifdef UF_IMMUTABLE + if (flags & EXT2_IMMUTABLE_FL) + bsd_flags |= UF_IMMUTABLE; +#endif +#ifdef UF_APPEND + if (flags & EXT2_APPEND_FL) + bsd_flags |= UF_APPEND; +#endif +#ifdef UF_NODUMP + if (flags & EXT2_NODUMP_FL) + bsd_flags |= UF_NODUMP; +#endif + + return chflags (name, bsd_flags); +#else /* !HAVE_CHFLAGS || (APPLE_DARWIN && HAVE_EXT2_IOCTLS) */ +#if HAVE_EXT2_IOCTLS + int fd, r, f, save_errno = 0; + struct stat buf; + + if (!lstat(name, &buf) && + !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) { + goto notsupp; + } +#if !APPLE_DARWIN + fd = open (name, OPEN_FLAGS); + if (fd == -1) + return -1; + f = (int) flags; + r = ioctl (fd, EXT2_IOC_SETFLAGS, &f); + if (r == -1) + save_errno = errno; + close (fd); + if (save_errno) + errno = save_errno; +#else /* APPLE_DARWIN */ + f = (int) flags; + return syscall(SYS_fsctl, name, EXT2_IOC_SETFLAGS, &f, 0); +#endif /* !APPLE_DARWIN */ + return r; + +notsupp: +#endif /* HAVE_EXT2_IOCTLS */ +#endif + errno = EOPNOTSUPP; + return -1; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/fsetproject.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/fsetproject.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,69 @@ +/* + * fgetproject.c --- get project id + * + * Copyright (C) 1999 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#include "config.h" +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_EXT2_IOCTLS +#include +#include +#include "project.h" +#endif + +#include "e2p.h" + +#ifdef O_LARGEFILE +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE) +#else +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK) +#endif + +int fsetproject(const char *name, unsigned long project) +{ +#ifndef FS_IOC_FSGETXATTR + errno = EOPNOTSUPP; + return -1; +#else + int fd, r, save_errno = 0; + struct fsxattr fsx; + + fd = open (name, OPEN_FLAGS); + if (fd == -1) + return -1; + r = ioctl (fd, FS_IOC_FSGETXATTR, &fsx); + if (r == -1) { + save_errno = errno; + goto errout; + } + fsx.fsx_projid = project; + r = ioctl (fd, FS_IOC_FSSETXATTR, &fsx); + if (r == -1) + save_errno = errno; +errout: + close (fd); + if (save_errno) + errno = save_errno; + return r; +#endif +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/fsetversion.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/fsetversion.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,72 @@ +/* + * fsetversion.c - Set a file version on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#include "config.h" +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#include +#if HAVE_SYS_IOCTL_H +#include +#endif + +#include "e2p.h" + +#ifdef O_LARGEFILE +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE) +#else +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK) +#endif + +int fsetversion (const char * name, unsigned long version) +{ +#if HAVE_EXT2_IOCTLS +#if !APPLE_DARWIN + int fd, r, ver, save_errno = 0; + + fd = open (name, OPEN_FLAGS); + if (fd == -1) + return -1; + ver = (int) version; + r = ioctl (fd, EXT2_IOC_SETVERSION, &ver); + if (r == -1) + save_errno = errno; + close (fd); + if (save_errno) + errno = save_errno; + return r; +#else + int ver = (int)version; + return syscall(SYS_fsctl, name, EXT2_IOC_SETVERSION, &ver, 0); +#endif +#else /* ! HAVE_EXT2_IOCTLS */ + extern int errno; + errno = EOPNOTSUPP; + return -1; +#endif /* ! HAVE_EXT2_IOCTLS */ +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/getflags.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/getflags.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,70 @@ +/* + * getflags.c - Get a file flags on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#include "config.h" +#if HAVE_ERRNO_H +#include +#endif +#include +#include +#if HAVE_EXT2_IOCTLS +#include +#endif + +#include "e2p.h" + +int getflags (int fd, unsigned long * flags) +{ + struct stat buf; +#if HAVE_STAT_FLAGS + + if (fstat (fd, &buf) == -1) + return -1; + + *flags = 0; +#ifdef UF_IMMUTABLE + if (buf.st_flags & UF_IMMUTABLE) + *flags |= EXT2_IMMUTABLE_FL; +#endif +#ifdef UF_APPEND + if (buf.st_flags & UF_APPEND) + *flags |= EXT2_APPEND_FL; +#endif +#ifdef UF_NODUMP + if (buf.st_flags & UF_NODUMP) + *flags |= EXT2_NODUMP_FL; +#endif + + return 0; +#else +#if HAVE_EXT2_IOCTLS + int r, f; + + if (!fstat(fd, &buf) && + !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) + goto notsupp; + r = ioctl(fd, EXT2_IOC_GETFLAGS, &f); + *flags = f; + + return r; +notsupp: +#endif /* HAVE_EXT2_IOCTLS */ +#endif + errno = EOPNOTSUPP; + return -1; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/getversion.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/getversion.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,42 @@ +/* + * getversion.c - Get a file version on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#include "config.h" +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_SYS_IOCTL_H +#include +#endif + +#include "e2p.h" + +int getversion (int fd, unsigned long * version) +{ +#if HAVE_EXT2_IOCTLS + int r, ver; + + r = ioctl (fd, EXT2_IOC_GETVERSION, &ver); + *version = ver; + return r; +#else /* ! HAVE_EXT2_IOCTLS */ + extern int errno; + errno = EOPNOTSUPP; + return -1; +#endif /* ! HAVE_EXT2_IOCTLS */ +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/hashstr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/hashstr.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,72 @@ +/* + * feature.c --- convert between features and strings + * + * Copyright (C) 1999 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include +#include +#include + +#include "e2p.h" + +struct hash { + int num; + const char *string; +}; + +static struct hash hash_list[] = { + { EXT2_HASH_LEGACY, "legacy" }, + { EXT2_HASH_HALF_MD4, "half_md4" }, + { EXT2_HASH_TEA, "tea" }, + { 0, 0 }, +}; + +const char *e2p_hash2string(int num) +{ + struct hash *p; + static char buf[20]; + + for (p = hash_list; p->string; p++) { + if (num == p->num) + return p->string; + } + sprintf(buf, "HASHALG_%d", num); + return buf; +} + +/* + * Returns the hash algorithm, or -1 on error + */ +int e2p_string2hash(char *string) +{ + struct hash *p; + char *eptr; + int num; + + for (p = hash_list; p->string; p++) { + if (!strcasecmp(string, p->string)) { + return p->num; + } + } + if (strncasecmp(string, "HASHALG_", 8)) + return -1; + + if (string[8] == 0) + return -1; + num = strtol(string+8, &eptr, 10); + if (num > 255 || num < 0) + return -1; + if (*eptr) + return -1; + return num; +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/iod.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/iod.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,76 @@ +/* + * iod.c - Iterate a function on each entry of a directory + * + * Copyright (C) 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#include "config.h" +#include "e2p.h" +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +int iterate_on_dir (const char * dir_name, + int (*func) (const char *, struct dirent *, void *), + void * private) +{ + DIR * dir; + struct dirent *de, *dep; + int max_len = -1, len, ret = 0; + +#if HAVE_PATHCONF && defined(_PC_NAME_MAX) + max_len = pathconf(dir_name, _PC_NAME_MAX); +#endif + if (max_len == -1) { +#ifdef _POSIX_NAME_MAX + max_len = _POSIX_NAME_MAX; +#else +#ifdef NAME_MAX + max_len = NAME_MAX; +#else + max_len = 256; +#endif /* NAME_MAX */ +#endif /* _POSIX_NAME_MAX */ + } + max_len += sizeof(struct dirent); + + de = malloc(max_len+1); + if (!de) + return -1; + memset(de, 0, max_len+1); + + dir = opendir (dir_name); + if (dir == NULL) { + free(de); + return -1; + } + while ((dep = readdir (dir))) { +#ifdef HAVE_RECLEN_DIRENT + len = dep->d_reclen; + if (len > max_len) + len = max_len; +#else + len = sizeof(struct dirent); +#endif + memcpy(de, dep, len); + if ((*func)(dir_name, de, private)) + ret++; + } + free(de); + closedir(dir); + return ret; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/ljs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/ljs.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,113 @@ +/* + * ljs.c - List the contents of an journal superblock + * + * Copyright (C) 1995, 1996, 1997 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include + +#include "ext2fs/ext2_fs.h" +#include "ext2fs/ext2fs.h" +#include "e2p.h" +#include "ext2fs/kernel-jbd.h" + +#ifdef WORDS_BIGENDIAN +#define e2p_be32(x) (x) +#else +static __u32 e2p_swab32(__u32 val) +{ + return ((val>>24) | ((val>>8)&0xFF00) | + ((val<<8)&0xFF0000) | (val<<24)); +} + +#define e2p_be32(x) e2p_swab32(x) +#endif + +static const char *journal_checksum_type_str(__u8 type) +{ + switch (type) { + case JBD2_CRC32C_CHKSUM: + return "crc32c"; + default: + return "unknown"; + } +} + +void e2p_list_journal_super(FILE *f, char *journal_sb_buf, + int exp_block_size, int flags) +{ + journal_superblock_t *jsb = (journal_superblock_t *) journal_sb_buf; + __u32 *mask_ptr, mask, m; + unsigned int size; + int j, printed = 0; + unsigned int i, nr_users; + + fprintf(f, "%s", "Journal features: "); + for (i=0, mask_ptr=&jsb->s_feature_compat; i <3; i++,mask_ptr++) { + mask = e2p_be32(*mask_ptr); + for (j=0,m=1; j < 32; j++, m<<=1) { + if (mask & m) { + fprintf(f, " %s", e2p_jrnl_feature2string(i, m)); + printed++; + } + } + } + if (printed == 0) + fprintf(f, " (none)"); + fputc('\n', f); + fputs("Journal size: ", f); + size = (ntohl(jsb->s_blocksize) / 1024) * ntohl(jsb->s_maxlen); + if (size < 8192) + fprintf(f, "%uk\n", size); + else + fprintf(f, "%uM\n", size >> 10); + nr_users = (unsigned int) ntohl(jsb->s_nr_users); + if (exp_block_size != (int) ntohl(jsb->s_blocksize)) + fprintf(f, "Journal block size: %u\n", + (unsigned int)ntohl(jsb->s_blocksize)); + fprintf(f, "Journal length: %u\n", + (unsigned int)ntohl(jsb->s_maxlen)); + if (ntohl(jsb->s_first) != 1) + fprintf(f, "Journal first block: %u\n", + (unsigned int)ntohl(jsb->s_first)); + fprintf(f, "Journal sequence: 0x%08x\n" + "Journal start: %u\n", + (unsigned int)ntohl(jsb->s_sequence), + (unsigned int)ntohl(jsb->s_start)); + if (nr_users != 1) + fprintf(f, "Journal number of users: %u\n", nr_users); + if (jsb->s_feature_compat & e2p_be32(JFS_FEATURE_COMPAT_CHECKSUM)) + fprintf(f, "%s", "Journal checksum type: crc32\n"); + if ((jsb->s_feature_incompat & + e2p_be32(JFS_FEATURE_INCOMPAT_CSUM_V3)) || + (jsb->s_feature_incompat & + e2p_be32(JFS_FEATURE_INCOMPAT_CSUM_V2))) + fprintf(f, "Journal checksum type: %s\n" + "Journal checksum: 0x%08x\n", + journal_checksum_type_str(jsb->s_checksum_type), + e2p_be32(jsb->s_checksum)); + if ((nr_users > 1) || + !e2p_is_null_uuid(&jsb->s_users[0])) { + for (i=0; i < nr_users && i < JFS_USERS_MAX; i++) { + printf(i ? " %s\n" + : "Journal users: %s\n", + e2p_uuid2str(&jsb->s_users[i * UUID_SIZE])); + } + } + if (jsb->s_errno != 0) + fprintf(f, "Journal errno: %d\n", + (int) ntohl(jsb->s_errno)); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/ls.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/ls.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,479 @@ +/* + * ls.c - List the contents of an ext2fs superblock + * + * Copyright (C) 1992, 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * Copyright (C) 1995, 1996, 1997 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include + +#include "e2p.h" +#include "support/quotaio.h" + +static void print_user (unsigned short uid, FILE *f) +{ + struct passwd *pw; + + fprintf(f, "%u ", uid); + pw = getpwuid (uid); + if (pw == NULL) + fprintf(f, "(user unknown)\n"); + else + fprintf(f, "(user %s)\n", pw->pw_name); +} + +static void print_group (unsigned short gid, FILE *f) +{ + struct group *gr; + + fprintf(f, "%u ", gid); + gr = getgrgid (gid); + if (gr == NULL) + fprintf(f, "(group unknown)\n"); + else + fprintf(f, "(group %s)\n", gr->gr_name); +} + +#define MONTH_INT (86400 * 30) +#define WEEK_INT (86400 * 7) +#define DAY_INT (86400) +#define HOUR_INT (60 * 60) +#define MINUTE_INT (60) + +static const char *interval_string(unsigned int secs) +{ + static char buf[256], tmp[80]; + int hr, min, num; + + buf[0] = 0; + + if (secs == 0) + return ""; + + if (secs >= MONTH_INT) { + num = secs / MONTH_INT; + secs -= num*MONTH_INT; + sprintf(buf, "%d month%s", num, (num>1) ? "s" : ""); + } + if (secs >= WEEK_INT) { + num = secs / WEEK_INT; + secs -= num*WEEK_INT; + sprintf(tmp, "%s%d week%s", buf[0] ? ", " : "", + num, (num>1) ? "s" : ""); + strcat(buf, tmp); + } + if (secs >= DAY_INT) { + num = secs / DAY_INT; + secs -= num*DAY_INT; + sprintf(tmp, "%s%d day%s", buf[0] ? ", " : "", + num, (num>1) ? "s" : ""); + strcat(buf, tmp); + } + if (secs > 0) { + hr = secs / HOUR_INT; + secs -= hr*HOUR_INT; + min = secs / MINUTE_INT; + secs -= min*MINUTE_INT; + sprintf(tmp, "%s%d:%02d:%02d", buf[0] ? ", " : "", + hr, min, secs); + strcat(buf, tmp); + } + return buf; +} + +static void print_features(struct ext2_super_block * s, FILE *f) +{ +#ifdef EXT2_DYNAMIC_REV + int i, j, printed=0; + __u32 *mask = &s->s_feature_compat, m; + + fprintf(f, "Filesystem features: "); + for (i=0; i <3; i++,mask++) { + for (j=0,m=1; j < 32; j++, m<<=1) { + if (*mask & m) { + fprintf(f, " %s", e2p_feature2string(i, m)); + printed++; + } + } + } + if (printed == 0) + fprintf(f, " (none)"); + fprintf(f, "\n"); +#endif +} + +static void print_mntopts(struct ext2_super_block * s, FILE *f) +{ +#ifdef EXT2_DYNAMIC_REV + int i, printed=0; + __u32 mask = s->s_default_mount_opts, m; + + fprintf(f, "Default mount options: "); + if (mask & EXT3_DEFM_JMODE) { + fprintf(f, " %s", e2p_mntopt2string(mask & EXT3_DEFM_JMODE)); + printed++; + } + for (i=0,m=1; i < 32; i++, m<<=1) { + if (m & EXT3_DEFM_JMODE) + continue; + if (mask & m) { + fprintf(f, " %s", e2p_mntopt2string(m)); + printed++; + } + } + if (printed == 0) + fprintf(f, " (none)"); + fprintf(f, "\n"); +#endif +} + +static void print_super_flags(struct ext2_super_block * s, FILE *f) +{ + int flags_found = 0; + + if (s->s_flags == 0) + return; + + fputs("Filesystem flags: ", f); + if (s->s_flags & EXT2_FLAGS_SIGNED_HASH) { + fputs("signed_directory_hash ", f); + flags_found++; + } + if (s->s_flags & EXT2_FLAGS_UNSIGNED_HASH) { + fputs("unsigned_directory_hash ", f); + flags_found++; + } + if (s->s_flags & EXT2_FLAGS_TEST_FILESYS) { + fputs("test_filesystem ", f); + flags_found++; + } + if (flags_found) + fputs("\n", f); + else + fputs("(none)\n", f); +} + +static __u64 e2p_blocks_count(struct ext2_super_block *super) +{ + return super->s_blocks_count | + (ext2fs_has_feature_64bit(super) ? + (__u64) super->s_blocks_count_hi << 32 : 0); +} + +static __u64 e2p_r_blocks_count(struct ext2_super_block *super) +{ + return super->s_r_blocks_count | + (ext2fs_has_feature_64bit(super) ? + (__u64) super->s_r_blocks_count_hi << 32 : 0); +} + +static __u64 e2p_free_blocks_count(struct ext2_super_block *super) +{ + return super->s_free_blocks_count | + (ext2fs_has_feature_64bit(super) ? + (__u64) super->s_free_blocks_hi << 32 : 0); +} + +#ifndef EXT2_INODE_SIZE +#define EXT2_INODE_SIZE(s) sizeof(struct ext2_inode) +#endif + +#ifndef EXT2_GOOD_OLD_REV +#define EXT2_GOOD_OLD_REV 0 +#endif + +static const char *checksum_type(__u8 type) +{ + switch (type) { + case EXT2_CRC32C_CHKSUM: + return "crc32c"; + default: + return "unknown"; + } +} + +static const char *quota_prefix[MAXQUOTAS] = { + [USRQUOTA] = "User quota inode:", + [GRPQUOTA] = "Group quota inode:", + [PRJQUOTA] = "Project quota inode:", +}; + +/** + * Convert type of quota to written representation + */ +static const char *quota_type2prefix(enum quota_type qtype) +{ + return quota_prefix[qtype]; +} + +void list_super2(struct ext2_super_block * sb, FILE *f) +{ + int inode_blocks_per_group; + char buf[80], *str; + time_t tm; + enum quota_type qtype; + + inode_blocks_per_group = (((sb->s_inodes_per_group * + EXT2_INODE_SIZE(sb)) + + EXT2_BLOCK_SIZE(sb) - 1) / + EXT2_BLOCK_SIZE(sb)); + if (sb->s_volume_name[0]) { + memset(buf, 0, sizeof(buf)); + strncpy(buf, sb->s_volume_name, sizeof(sb->s_volume_name)); + } else + strcpy(buf, ""); + fprintf(f, "Filesystem volume name: %s\n", buf); + if (sb->s_last_mounted[0]) { + memset(buf, 0, sizeof(buf)); + strncpy(buf, sb->s_last_mounted, sizeof(sb->s_last_mounted)); + } else + strcpy(buf, ""); + fprintf(f, "Last mounted on: %s\n", buf); + fprintf(f, "Filesystem UUID: %s\n", e2p_uuid2str(sb->s_uuid)); + fprintf(f, "Filesystem magic number: 0x%04X\n", sb->s_magic); + fprintf(f, "Filesystem revision #: %d", sb->s_rev_level); + if (sb->s_rev_level == EXT2_GOOD_OLD_REV) { + fprintf(f, " (original)\n"); +#ifdef EXT2_DYNAMIC_REV + } else if (sb->s_rev_level == EXT2_DYNAMIC_REV) { + fprintf(f, " (dynamic)\n"); +#endif + } else + fprintf(f, " (unknown)\n"); + print_features(sb, f); + print_super_flags(sb, f); + print_mntopts(sb, f); + if (sb->s_mount_opts[0]) + fprintf(f, "Mount options: %s\n", sb->s_mount_opts); + fprintf(f, "Filesystem state: "); + print_fs_state (f, sb->s_state); + fprintf(f, "\n"); + fprintf(f, "Errors behavior: "); + print_fs_errors(f, sb->s_errors); + fprintf(f, "\n"); + str = e2p_os2string(sb->s_creator_os); + fprintf(f, "Filesystem OS type: %s\n", str); + free(str); + fprintf(f, "Inode count: %u\n", sb->s_inodes_count); + fprintf(f, "Block count: %llu\n", e2p_blocks_count(sb)); + fprintf(f, "Reserved block count: %llu\n", e2p_r_blocks_count(sb)); + if (sb->s_overhead_blocks) + fprintf(f, "Overhead blocks: %u\n", + sb->s_overhead_blocks); + fprintf(f, "Free blocks: %llu\n", e2p_free_blocks_count(sb)); + fprintf(f, "Free inodes: %u\n", sb->s_free_inodes_count); + fprintf(f, "First block: %u\n", sb->s_first_data_block); + fprintf(f, "Block size: %u\n", EXT2_BLOCK_SIZE(sb)); + if (ext2fs_has_feature_bigalloc(sb)) + fprintf(f, "Cluster size: %u\n", + EXT2_CLUSTER_SIZE(sb)); + else + fprintf(f, "Fragment size: %u\n", + EXT2_CLUSTER_SIZE(sb)); + if (ext2fs_has_feature_64bit(sb)) + fprintf(f, "Group descriptor size: %u\n", sb->s_desc_size); + if (sb->s_reserved_gdt_blocks) + fprintf(f, "Reserved GDT blocks: %u\n", + sb->s_reserved_gdt_blocks); + fprintf(f, "Blocks per group: %u\n", sb->s_blocks_per_group); + if (ext2fs_has_feature_bigalloc(sb)) + fprintf(f, "Clusters per group: %u\n", + sb->s_clusters_per_group); + else + fprintf(f, "Fragments per group: %u\n", + sb->s_clusters_per_group); + fprintf(f, "Inodes per group: %u\n", sb->s_inodes_per_group); + fprintf(f, "Inode blocks per group: %u\n", inode_blocks_per_group); + if (sb->s_raid_stride) + fprintf(f, "RAID stride: %u\n", + sb->s_raid_stride); + if (sb->s_raid_stripe_width) + fprintf(f, "RAID stripe width: %u\n", + sb->s_raid_stripe_width); + if (sb->s_first_meta_bg) + fprintf(f, "First meta block group: %u\n", + sb->s_first_meta_bg); + if (sb->s_log_groups_per_flex) + fprintf(f, "Flex block group size: %u\n", + 1 << sb->s_log_groups_per_flex); + if (sb->s_mkfs_time) { + tm = sb->s_mkfs_time; + fprintf(f, "Filesystem created: %s", ctime(&tm)); + } + tm = sb->s_mtime; + fprintf(f, "Last mount time: %s", + sb->s_mtime ? ctime(&tm) : "n/a\n"); + tm = sb->s_wtime; + fprintf(f, "Last write time: %s", ctime(&tm)); + fprintf(f, "Mount count: %u\n", sb->s_mnt_count); + fprintf(f, "Maximum mount count: %d\n", sb->s_max_mnt_count); + tm = sb->s_lastcheck; + fprintf(f, "Last checked: %s", ctime(&tm)); + fprintf(f, "Check interval: %u (%s)\n", sb->s_checkinterval, + interval_string(sb->s_checkinterval)); + if (sb->s_checkinterval) + { + time_t next; + + next = sb->s_lastcheck + sb->s_checkinterval; + fprintf(f, "Next check after: %s", ctime(&next)); + } +#define POW2(x) ((__u64) 1 << (x)) + if (sb->s_kbytes_written) { + fprintf(f, "Lifetime writes: "); + if (sb->s_kbytes_written < POW2(13)) + fprintf(f, "%llu kB\n", sb->s_kbytes_written); + else if (sb->s_kbytes_written < POW2(23)) + fprintf(f, "%llu MB\n", + (sb->s_kbytes_written + POW2(9)) >> 10); + else if (sb->s_kbytes_written < POW2(33)) + fprintf(f, "%llu GB\n", + (sb->s_kbytes_written + POW2(19)) >> 20); + else if (sb->s_kbytes_written < POW2(43)) + fprintf(f, "%llu TB\n", + (sb->s_kbytes_written + POW2(29)) >> 30); + else + fprintf(f, "%llu PB\n", + (sb->s_kbytes_written + POW2(39)) >> 40); + } + fprintf(f, "Reserved blocks uid: "); + print_user(sb->s_def_resuid, f); + fprintf(f, "Reserved blocks gid: "); + print_group(sb->s_def_resgid, f); + if (sb->s_rev_level >= EXT2_DYNAMIC_REV) { + fprintf(f, "First inode: %d\n", sb->s_first_ino); + fprintf(f, "Inode size: %d\n", sb->s_inode_size); + if (sb->s_min_extra_isize) + fprintf(f, "Required extra isize: %d\n", + sb->s_min_extra_isize); + if (sb->s_want_extra_isize) + fprintf(f, "Desired extra isize: %d\n", + sb->s_want_extra_isize); + } + if (!e2p_is_null_uuid(sb->s_journal_uuid)) + fprintf(f, "Journal UUID: %s\n", + e2p_uuid2str(sb->s_journal_uuid)); + if (sb->s_journal_inum) + fprintf(f, "Journal inode: %u\n", + sb->s_journal_inum); + if (sb->s_journal_dev) + fprintf(f, "Journal device: 0x%04x\n", + sb->s_journal_dev); + if (sb->s_last_orphan) + fprintf(f, "First orphan inode: %u\n", + sb->s_last_orphan); + if (ext2fs_has_feature_dir_index(sb) || + sb->s_def_hash_version) + fprintf(f, "Default directory hash: %s\n", + e2p_hash2string(sb->s_def_hash_version)); + if (!e2p_is_null_uuid(sb->s_hash_seed)) + fprintf(f, "Directory Hash Seed: %s\n", + e2p_uuid2str(sb->s_hash_seed)); + if (sb->s_jnl_backup_type) { + fprintf(f, "Journal backup: "); + switch (sb->s_jnl_backup_type) { + case 1: + fprintf(f, "inode blocks\n"); + break; + default: + fprintf(f, "type %u\n", sb->s_jnl_backup_type); + } + } + if (sb->s_backup_bgs[0] || sb->s_backup_bgs[1]) { + fprintf(f, "Backup block groups: "); + if (sb->s_backup_bgs[0]) + fprintf(f, "%u ", sb->s_backup_bgs[0]); + if (sb->s_backup_bgs[1]) + fprintf(f, "%u ", sb->s_backup_bgs[1]); + fputc('\n', f); + } + if (sb->s_snapshot_inum) { + fprintf(f, "Snapshot inode: %u\n", + sb->s_snapshot_inum); + fprintf(f, "Snapshot ID: %u\n", + sb->s_snapshot_id); + fprintf(f, "Snapshot reserved blocks: %llu\n", + sb->s_snapshot_r_blocks_count); + } + if (sb->s_snapshot_list) + fprintf(f, "Snapshot list head: %u\n", + sb->s_snapshot_list); + if (sb->s_error_count) + fprintf(f, "FS Error count: %u\n", + sb->s_error_count); + if (sb->s_first_error_time) { + tm = sb->s_first_error_time; + fprintf(f, "First error time: %s", ctime(&tm)); + memset(buf, 0, sizeof(buf)); + strncpy(buf, (char *)sb->s_first_error_func, + sizeof(sb->s_first_error_func)); + fprintf(f, "First error function: %s\n", buf); + fprintf(f, "First error line #: %u\n", + sb->s_first_error_line); + fprintf(f, "First error inode #: %u\n", + sb->s_first_error_ino); + fprintf(f, "First error block #: %llu\n", + sb->s_first_error_block); + } + if (sb->s_last_error_time) { + tm = sb->s_last_error_time; + fprintf(f, "Last error time: %s", ctime(&tm)); + memset(buf, 0, sizeof(buf)); + strncpy(buf, (char *)sb->s_last_error_func, + sizeof(sb->s_last_error_func)); + fprintf(f, "Last error function: %s\n", buf); + fprintf(f, "Last error line #: %u\n", + sb->s_last_error_line); + fprintf(f, "Last error inode #: %u\n", + sb->s_last_error_ino); + fprintf(f, "Last error block #: %llu\n", + sb->s_last_error_block); + } + if (ext2fs_has_feature_mmp(sb)) { + fprintf(f, "MMP block number: %llu\n", + (long long)sb->s_mmp_block); + fprintf(f, "MMP update interval: %u\n", + sb->s_mmp_update_interval); + } + for (qtype = 0; qtype < MAXQUOTAS; qtype++) { + if (*quota_sb_inump(sb, qtype) != 0) + fprintf(f, "%-26s%u\n", + quota_type2prefix(qtype), + *quota_sb_inump(sb, qtype)); + } + + if (ext2fs_has_feature_metadata_csum(sb)) { + fprintf(f, "Checksum type: %s\n", + checksum_type(sb->s_checksum_type)); + fprintf(f, "Checksum: 0x%08x\n", + sb->s_checksum); + } + if (!e2p_is_null_uuid(sb->s_encrypt_pw_salt)) + fprintf(f, "Encryption PW Salt: %s\n", + e2p_uuid2str(sb->s_encrypt_pw_salt)); + + if (ext2fs_has_feature_csum_seed(sb)) + fprintf(f, "Checksum seed: 0x%08x\n", + sb->s_checksum_seed); +} + +void list_super (struct ext2_super_block * s) +{ + list_super2(s, stdout); +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/mntopts.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/mntopts.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,150 @@ +/* + * mountopts.c --- convert between default mount options and strings + * + * Copyright (C) 2002 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include + +#include "e2p.h" + +struct mntopt { + unsigned int mask; + const char *string; +}; + +static struct mntopt mntopt_list[] = { + { EXT2_DEFM_DEBUG, "debug" }, + { EXT2_DEFM_BSDGROUPS, "bsdgroups" }, + { EXT2_DEFM_XATTR_USER, "user_xattr" }, + { EXT2_DEFM_ACL, "acl" }, + { EXT2_DEFM_UID16, "uid16" }, + { EXT3_DEFM_JMODE_DATA, "journal_data" }, + { EXT3_DEFM_JMODE_ORDERED, "journal_data_ordered" }, + { EXT3_DEFM_JMODE_WBACK, "journal_data_writeback" }, + { EXT4_DEFM_NOBARRIER, "nobarrier" }, + { EXT4_DEFM_BLOCK_VALIDITY, "block_validity" }, + { EXT4_DEFM_DISCARD, "discard"}, + { EXT4_DEFM_NODELALLOC, "nodelalloc"}, + { 0, 0 }, +}; + +const char *e2p_mntopt2string(unsigned int mask) +{ + struct mntopt *f; + static char buf[20]; + int fnum; + + for (f = mntopt_list; f->string; f++) { + if (mask == f->mask) + return f->string; + } + for (fnum = 0; mask >>= 1; fnum++); + sprintf(buf, "MNTOPT_%d", fnum); + return buf; +} + +int e2p_string2mntopt(char *string, unsigned int *mask) +{ + struct mntopt *f; + char *eptr; + int num; + + for (f = mntopt_list; f->string; f++) { + if (!strcasecmp(string, f->string)) { + *mask = f->mask; + return 0; + } + } + if (strncasecmp(string, "MNTOPT_", 7)) + return 1; + + if (string[8] == 0) + return 1; + num = strtol(string+8, &eptr, 10); + if (num > 31 || num < 0) + return 1; + if (*eptr) + return 1; + *mask = 1 << num; + return 0; +} + +static char *skip_over_blanks(char *cp) +{ + while (*cp && isspace(*cp)) + cp++; + return cp; +} + +static char *skip_over_word(char *cp) +{ + while (*cp && !isspace(*cp) && *cp != ',') + cp++; + return cp; +} + +/* + * Edit a mntopt set array as requested by the user. The ok + * parameter, if non-zero, allows the application to limit what + * mntopts the user is allowed to set or clear using this function. + */ +int e2p_edit_mntopts(const char *str, __u32 *mntopts, __u32 ok) +{ + char *cp, *buf, *next; + int neg; + unsigned int mask; + int rc = 0; + + buf = malloc(strlen(str)+1); + if (!buf) + return 1; + strcpy(buf, str); + cp = buf; + while (cp && *cp) { + neg = 0; + cp = skip_over_blanks(cp); + next = skip_over_word(cp); + if (*next == 0) + next = 0; + else + *next = 0; + switch (*cp) { + case '-': + case '^': + neg++; + /* fallthrough */ + case '+': + cp++; + break; + } + if (e2p_string2mntopt(cp, &mask)) { + rc = 1; + break; + } + if (ok && !(ok & mask)) { + rc = 1; + break; + } + if (mask & EXT3_DEFM_JMODE) + *mntopts &= ~EXT3_DEFM_JMODE; + if (neg) + *mntopts &= ~mask; + else + *mntopts |= mask; + cp = next ? next+1 : 0; + } + free(buf); + return rc; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/ostype.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/ostype.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,79 @@ +/* + * getostype.c - Get the Filesystem OS type + * + * Copyright (C) 2004,2005 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include "e2p.h" +#include +#include + +static const char *os_tab[] = + { "Linux", + "Hurd", + "Masix", + "FreeBSD", + "Lites", + 0 }; + +/* + * Convert an os_type to a string + */ +char *e2p_os2string(int os_type) +{ + const char *os; + char *ret; + + if (os_type >= 0 && os_type <= EXT2_OS_LITES) + os = os_tab[os_type]; + else + os = "(unknown os)"; + + ret = malloc(strlen(os)+1); + if (ret) + strcpy(ret, os); + return ret; +} + +/* + * Convert an os_type to a string + */ +int e2p_string2os(char *str) +{ + const char **cpp; + int i = 0; + + for (cpp = os_tab; *cpp; cpp++, i++) { + if (!strcasecmp(str, *cpp)) + return i; + } + return -1; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + char *s; + int i, os; + + for (i=0; i <= EXT2_OS_LITES; i++) { + s = e2p_os2string(i); + os = e2p_string2os(s); + printf("%d: %s (%d)\n", i, s, os); + free(s); + if (i != os) { + fprintf(stderr, "Failure!\n"); + exit(1); + } + } + exit(0); +} +#endif + + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/parse_num.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/parse_num.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,91 @@ +/* + * parse_num.c - Parse the number of blocks + * + * Copyright (C) 2004,2005 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include "e2p.h" + +#include + +unsigned long long parse_num_blocks2(const char *arg, int log_block_size) +{ + char *p; + unsigned long long num; + + num = strtoull(arg, &p, 0); + + if (p[0] && p[1]) + return 0; + + switch (*p) { /* Using fall-through logic */ + case 'T': case 't': + num <<= 10; + /* fallthrough */ + case 'G': case 'g': + num <<= 10; + /* fallthrough */ + case 'M': case 'm': + num <<= 10; + /* fallthrough */ + case 'K': case 'k': + if (log_block_size < 0) + num <<= 10; + else + num >>= log_block_size; + break; + case 's': + if (log_block_size < 0) + num <<= 9; + else + num >>= (1+log_block_size); + break; + case '\0': + break; + default: + return 0; + } + return num; +} + +unsigned long parse_num_blocks(const char *arg, int log_block_size) +{ + return parse_num_blocks2(arg, log_block_size); +} + +#ifdef DEBUG +#include +#include + +main(int argc, char **argv) +{ + unsigned long num; + int log_block_size = 0; + + if (argc != 2 && argc != 3) { + fprintf(stderr, "Usage: %s arg [log_block_size]\n", argv[0]); + exit(1); + } + + if (argc == 3) { + char *p; + + log_block_size = strtol(argv[2], &p, 0); + if (*p) { + fprintf(stderr, "Bad log_block_size: %s\n", argv[2]); + exit(1); + } + } + + num = parse_num_blocks(argv[1], log_block_size); + + printf("Parsed number: %lu\n", num); + exit(0); +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/pe.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/pe.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,40 @@ +/* + * pe.c - Print a second extended filesystem errors behavior + * + * Copyright (C) 1992, 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +/* + * History: + * 94/01/09 - Creation + */ + +#include "config.h" +#include + +#include "e2p.h" + +void print_fs_errors (FILE * f, unsigned short errors) +{ + switch (errors) + { + case EXT2_ERRORS_CONTINUE: + fprintf (f, "Continue"); + break; + case EXT2_ERRORS_RO: + fprintf (f, "Remount read-only"); + break; + case EXT2_ERRORS_PANIC: + fprintf (f, "Panic"); + break; + default: + fprintf (f, "Unknown (continue)"); + } +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/percent.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/percent.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,67 @@ +/* + * percent.c - Take percentage of a number + * + * Copyright (C) 2006 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include "e2p.h" + +#include + +/* + * We work really hard to calculate this accurately, while avoiding + * an overflow. "Is there a hyphen in anal-retentive?" :-) + */ +unsigned int e2p_percent(int percent, unsigned int base) +{ + unsigned int mask = ~((1 << (sizeof(unsigned int) - 1) * 8) - 1); + + if (!percent) + return 0; + if (100 % percent == 0) + return base / (100 / percent); + if (mask & base) + return (base / 100) * percent; + return base * percent / 100; +} + +#ifdef DEBUG +#include +#include + +main(int argc, char **argv) +{ + unsigned int base; + int percent; + char *p; + int log_block_size = 0; + + if (argc != 3) { + fprintf(stderr, "Usage: %s percent base\n", argv[0]); + exit(1); + } + + percent = strtoul(argv[1], &p, 0); + if (p[0] && p[1]) { + fprintf(stderr, "Bad percent: %s\n", argv[1]); + exit(1); + } + + base = strtoul(argv[2], &p, 0); + if (p[0] && p[1]) { + fprintf(stderr, "Bad base: %s\n", argv[2]); + exit(1); + } + + printf("%d percent of %u is %u.\n", percent, base, + e2p_percent(percent, base)); + + exit(0); +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/pf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/pf.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,77 @@ +/* + * pf.c - Print file attributes on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#include "config.h" +#include + +#include "e2p.h" + +struct flags_name { + unsigned long flag; + const char *short_name; + const char *long_name; +}; + +static struct flags_name flags_array[] = { + { EXT2_SECRM_FL, "s", "Secure_Deletion" }, + { EXT2_UNRM_FL, "u" , "Undelete" }, + { EXT2_SYNC_FL, "S", "Synchronous_Updates" }, + { EXT2_DIRSYNC_FL, "D", "Synchronous_Directory_Updates" }, + { EXT2_IMMUTABLE_FL, "i", "Immutable" }, + { EXT2_APPEND_FL, "a", "Append_Only" }, + { EXT2_NODUMP_FL, "d", "No_Dump" }, + { EXT2_NOATIME_FL, "A", "No_Atime" }, + { EXT2_COMPR_FL, "c", "Compression_Requested" }, + { EXT4_ENCRYPT_FL, "E", "Encrypted" }, + { EXT3_JOURNAL_DATA_FL, "j", "Journaled_Data" }, + { EXT2_INDEX_FL, "I", "Indexed_directory" }, + { EXT2_NOTAIL_FL, "t", "No_Tailmerging" }, + { EXT2_TOPDIR_FL, "T", "Top_of_Directory_Hierarchies" }, + { EXT4_EXTENTS_FL, "e", "Extents" }, + { FS_NOCOW_FL, "C", "No_COW" }, + { EXT4_INLINE_DATA_FL, "N", "Inline_Data" }, + { EXT4_PROJINHERIT_FL, "P", "Project_Hierarchy" }, + { EXT4_VERITY_FL, "V", "Verity" }, + { 0, NULL, NULL } +}; + +void print_flags (FILE * f, unsigned long flags, unsigned options) +{ + int long_opt = (options & PFOPT_LONG); + struct flags_name *fp; + int first = 1; + + for (fp = flags_array; fp->flag != 0; fp++) { + if (flags & fp->flag) { + if (long_opt) { + if (first) + first = 0; + else + fputs(", ", f); + fputs(fp->long_name, f); + } else + fputs(fp->short_name, f); + } else { + if (!long_opt) + fputs("-", f); + } + } + if (long_opt && first) + fputs("---", f); +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/project.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/project.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,27 @@ +/* + * project.h + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include + +#if defined(__linux__) && !defined(FS_IOC_FSGETXATTR) +#define FS_IOC_FSGETXATTR _IOR('X', 31, struct fsxattr) +#define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr) + +/* + * Structure for FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR. + */ +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 + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/ps.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/ps.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,32 @@ +/* + * ps.c - Print filesystem state + * + * Copyright (C) 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +/* + * History: + * 93/12/22 - Creation + */ + +#include "config.h" +#include + +#include "e2p.h" + +void print_fs_state (FILE * f, unsigned short state) +{ + if (state & EXT2_VALID_FS) + fprintf (f, " clean"); + else + fprintf (f, " not clean"); + if (state & EXT2_ERROR_FS) + fprintf (f, " with errors"); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/setflags.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/setflags.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,77 @@ +/* + * setflags.c - Set a file flags on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#include "config.h" +#if HAVE_ERRNO_H +#include +#endif +#include +#include +#if HAVE_EXT2_IOCTLS +#include +#endif + +#include "e2p.h" + +/* + * Deal with lame glibc's that define this function without actually + * implementing it. Can you say "attractive nuisance", boys and girls? + * I knew you could! + */ +#ifdef __linux__ +#undef HAVE_CHFLAGS +#endif + +int setflags (int fd, unsigned long flags) +{ +#if HAVE_CHFLAGS + unsigned long bsd_flags = 0; + +#ifdef UF_IMMUTABLE + if (flags & EXT2_IMMUTABLE_FL) + bsd_flags |= UF_IMMUTABLE; +#endif +#ifdef UF_APPEND + if (flags & EXT2_APPEND_FL) + bsd_flags |= UF_APPEND; +#endif +#ifdef UF_NODUMP + if (flags & EXT2_NODUMP_FL) + bsd_flags |= UF_NODUMP; +#endif + + return fchflags (fd, bsd_flags); +#else /* ! HAVE_CHFLAGS */ +#if HAVE_EXT2_IOCTLS + struct stat buf; + int f; + + if (!fstat(fd, &buf) && + !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) { + errno = EOPNOTSUPP; + return -1; + } + f = (int) flags; + + return ioctl(fd, EXT2_IOC_SETFLAGS, &f); +#else + errno = EOPNOTSUPP; + return -1; +#endif /* HAVE_EXT2_IOCTLS */ +#endif /* HAVE_CHFLAGS */ +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/setversion.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/setversion.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,41 @@ +/* + * setversion.c - Set a file version on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#include "config.h" +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_SYS_IOCTL_H +#include +#endif + +#include "e2p.h" + +int setversion (int fd, unsigned long version) +{ +#if HAVE_EXT2_IOCTLS + int ver; + + ver = (int) version; + return ioctl (fd, EXT2_IOC_SETVERSION, &ver); +#else /* ! HAVE_EXT2_IOCTLS */ + extern int errno; + errno = EOPNOTSUPP; + return -1; +#endif /* ! HAVE_EXT2_IOCTLS */ +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libe2p/uuid.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libe2p/uuid.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,85 @@ +/* + * uuid.c -- utility routines for manipulating UUID's. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include + +#include "e2p.h" + +struct uuid { + __u32 time_low; + __u16 time_mid; + __u16 time_hi_and_version; + __u16 clock_seq; + __u8 node[6]; +}; + +/* Returns 1 if the uuid is the NULL uuid */ +int e2p_is_null_uuid(void *uu) +{ + __u8 *cp; + int i; + + for (i=0, cp = uu; i < 16; i++) + if (*cp++) + return 0; + return 1; +} + +static void e2p_unpack_uuid(void *in, struct uuid *uu) +{ + __u8 *ptr = in; + __u32 tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + tmp = (tmp << 8) | *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_low = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_mid = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_hi_and_version = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->clock_seq = tmp; + + memcpy(uu->node, ptr, 6); +} + +void e2p_uuid_to_str(void *uu, char *out) +{ + struct uuid uuid; + + e2p_unpack_uuid(uu, &uuid); + sprintf(out, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, + uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, + uuid.node[0], uuid.node[1], uuid.node[2], + uuid.node[3], uuid.node[4], uuid.node[5]); +} + +const char *e2p_uuid2str(void *uu) +{ + static char buf[80]; + + if (e2p_is_null_uuid(uu)) + return ""; + e2p_uuid_to_str(uu, buf); + return buf; +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libet/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libet/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../../.. + +TARGET = libet.a libet.so +PC_FILENAME = libet +SRC_C = error_message.c et_name.c init_et.c com_err.c com_right.c + +PRIVATE_INCDIR += $(PKGDIR)/lib $(PKGDIR)/include/libet $(PKGDIR)/include/libet/et +CONTRIB_INCDIR = libet + +REQUIRES_LIBS = libc_support_misc + +include $(L4DIR)/mk/lib.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libet/com_err.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libet/com_err.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,104 @@ +/* + * Copyright 1987, 1988 by MIT Student Information Processing Board. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose is hereby granted, provided that + * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. M.I.T. and the + * M.I.T. S.I.P.B. make no representations about the suitability of + * this software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +#include "config.h" +#include +#ifdef HAVE_TERMIOS_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include "com_err.h" +#include "error_table.h" +#include "internal.h" + +static void +default_com_err_proc (const char *whoami, errcode_t code, const + char *fmt, va_list args) + COM_ERR_ATTR((format(printf, 3, 0))); + +static void +default_com_err_proc (const char *whoami, errcode_t code, const + char *fmt, va_list args) +{ + int do_cr = 1, fd = fileno(stderr); + + if (whoami) { + fputs(whoami, stderr); + fputs(": ", stderr); + } + if (code) { + fputs(error_message(code), stderr); + fputs(" ", stderr); + } + if (fmt) { + vfprintf (stderr, fmt, args); + } + if (!isatty(fd)) + do_cr = 0; +#ifdef HAVE_TERMIOS_H + else { + struct termios t; + + if ((tcgetattr(fd, &t)) == 0 && + (t.c_oflag & OPOST) && (t.c_oflag & ONLCR)) + do_cr = 0; + } +#endif + if (do_cr) + fputc('\r', stderr); + fputc('\n', stderr); + fflush(stderr); +} + +typedef void (*errf) (const char *, errcode_t, const char *, va_list); + +errf com_err_hook = default_com_err_proc; + +void com_err_va (const char *whoami, errcode_t code, const char *fmt, + va_list args) +{ + (*com_err_hook) (whoami, code, fmt, args); +} + +void com_err (const char *whoami, + errcode_t code, + const char *fmt, ...) +{ + va_list pvar; + + if (!com_err_hook) + com_err_hook = default_com_err_proc; + va_start(pvar, fmt); + com_err_va (whoami, code, fmt, pvar); + va_end(pvar); +} + +errf set_com_err_hook(errf new_proc) +{ + errf x = com_err_hook; + + if (new_proc) + com_err_hook = new_proc; + else + com_err_hook = default_com_err_proc; + + return x; +} + +errf reset_com_err_hook(void) { + errf x = com_err_hook; + com_err_hook = default_com_err_proc; + return x; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libet/com_right.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libet/com_right.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,120 @@ +/* + * com_right.c -- provide Heimdall / Kerberos4kth com_err interfaces + * for backwards compatibility + * + * Copyright (c) 2003 by Theodore Ts'o + * + * Taken from lib/com_err/error.c from Kerberos4kth distribution. + * + * Copyright (c) 1997, 1998, 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * 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. + * + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + */ + +#include "config.h" +#include +#include +#include +#include "com_err.h" +#include "error_table.h" + +const char * +com_right(struct et_list *list, long code) +{ + struct et_list *p; + for (p = list; p; p = p->next) { + if (code >= p->table->base && code < p->table->base + p->table->n_msgs) + return p->table->msgs[code - p->table->base]; + } + return NULL; +} + +const char * +com_right_r(struct et_list *list, long code, char *str, size_t len) +{ + struct et_list *p; + for (p = list; p; p = p->next) { + if ((code >= p->table->base) && + (code < p->table->base + p->table->n_msgs)) { + strncpy(str, p->table->msgs[code - p->table->base], len); + str[len-1] = '\0'; + return str; + } + } + return NULL; +} + +struct foobar { + struct et_list etl; + struct error_table tab; +}; + +/* + * We provide this routine for compatibility with Heimdall generated + * foo_err.c files, but we don't use this ourselves for foo_err.c + * files generated by our compile_et. This is so our foo_err.c + * files can be used with older com_err libraries without running + * afoul of dependencies. + */ +void +initialize_error_table_r(struct et_list **list, + const char **messages, + int num_errors, + long base) +{ + struct et_list *et, **end; + struct error_table *tab; + struct foobar *f; + + for (end = list, et = *list; et; end = &et->next, et = et->next) + if (et->table->msgs == messages) + return; + f = malloc(sizeof(*f)); + if (f == NULL) + return; + et = &f->etl; + et->table = tab = &f->tab; + tab->msgs = messages; + tab->n_msgs = num_errors; + tab->base = base; + et->next = NULL; + *end = et; +} + + +void +free_error_table(struct et_list *et) +{ + while(et){ + struct et_list *p = et; + et = et->next; + free(p); + } +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libet/error_message.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libet/error_message.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,350 @@ +/* + * $Header$ + * $Source$ + * $Locker$ + * + * Copyright 1987 by the Student Information Processing Board + * of the Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose is hereby granted, provided that + * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. M.I.T. and the + * M.I.T. S.I.P.B. make no representations about the suitability of + * this software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +#include "config.h" +#include +#include +#include +#include +#ifdef HAVE_SYS_PRCTL_H +#include +#else +#define PR_GET_DUMPABLE 3 +#endif +#if (!defined(HAVE_PRCTL) && defined(linux)) +#include +#endif +#ifdef HAVE_SEMAPHORE_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_FCNTL +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#include "com_err.h" +#include "error_table.h" +#include "internal.h" + +#ifdef TLS +#define THREAD_LOCAL static TLS +#else +#define THREAD_LOCAL static +#endif + +THREAD_LOCAL char buffer[25]; + +struct et_list * _et_list = (struct et_list *) NULL; +struct et_list * _et_dynamic_list = (struct et_list *) NULL; + +#ifdef __GNUC__ +#define COMERR_ATTR(x) __attribute__(x) +#else +#define COMERR_ATTR(x) +#endif + +#ifdef HAVE_SEM_INIT +static sem_t _et_lock; +static int _et_lock_initialized; + +static void COMERR_ATTR((constructor)) setup_et_lock(void) +{ + sem_init(&_et_lock, 0, 1); + _et_lock_initialized = 1; +} + +static void COMERR_ATTR((destructor)) fini_et_lock(void) +{ + sem_destroy(&_et_lock); + _et_lock_initialized = 0; +} +#endif + + +int et_list_lock(void) +{ +#ifdef HAVE_SEM_INIT + if (!_et_lock_initialized) + setup_et_lock(); + return sem_wait(&_et_lock); +#else + return 0; +#endif +} + +int et_list_unlock(void) +{ +#ifdef HAVE_SEM_INIT + if (_et_lock_initialized) + return sem_post(&_et_lock); +#endif + return 0; +} + +typedef char *(*gettextf) (const char *); + +static gettextf com_err_gettext = NULL; + +gettextf set_com_err_gettext(gettextf new_proc) +{ + gettextf x = com_err_gettext; + + com_err_gettext = new_proc; + + return x; +} + + +const char * error_message (errcode_t code) +{ + int offset; + struct et_list *et; + errcode_t table_num; + int started = 0; + char *cp; + + offset = (int) (code & ((1<next) { + if ((et->table->base & 0xffffffL) == (table_num & 0xffffffL)) { + /* This is the right table */ + if (et->table->n_msgs <= offset) { + break; + } else { + const char *msg = et->table->msgs[offset]; + et_list_unlock(); + if (com_err_gettext) + return (*com_err_gettext)(msg); + else + return msg; + } + } + } + for (et = _et_dynamic_list; et; et = et->next) { + if ((et->table->base & 0xffffffL) == (table_num & 0xffffffL)) { + /* This is the right table */ + if (et->table->n_msgs <= offset) { + break; + } else { + const char *msg = et->table->msgs[offset]; + et_list_unlock(); + if (com_err_gettext) + return (*com_err_gettext)(msg); + else + return msg; + } + } + } + et_list_unlock(); +oops: + strcpy (buffer, "Unknown code "); + if (table_num) { + strcat (buffer, error_table_name (table_num)); + strcat (buffer, " "); + } + for (cp = buffer; *cp; cp++) + ; + if (offset >= 100) { + *cp++ = '0' + offset / 100; + offset %= 100; + started++; + } + if (started || offset >= 10) { + *cp++ = '0' + offset / 10; + offset %= 10; + } + *cp++ = '0' + offset; + *cp = '\0'; + return(buffer); +} + +/* + * This routine will only return a value if the we are not running as + * a privileged process. + */ +static char *safe_getenv(const char *arg) +{ +#if !defined(_WIN32) + if ((getuid() != geteuid()) || (getgid() != getegid())) + return NULL; +#endif +#if HAVE_PRCTL + if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) + return NULL; +#else +#if (defined(linux) && defined(SYS_prctl)) + if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) + return NULL; +#endif +#endif + +#if defined(HAVE_SECURE_GETENV) + return secure_getenv(arg); +#elif defined(HAVE___SECURE_GETENV) + return __secure_getenv(arg); +#else + return getenv(arg); +#endif +} + +#define DEBUG_INIT 0x8000 +#define DEBUG_ADDREMOVE 0x0001 + +static int debug_mask = 0; +static FILE *debug_f = 0; + +static void init_debug(void) +{ + char *dstr, *fn, *tmp; + int fd, flags; + + if (debug_mask & DEBUG_INIT) + return; + + dstr = getenv("COMERR_DEBUG"); + if (dstr) { + debug_mask = strtoul(dstr, &tmp, 0); + if (*tmp || errno) + debug_mask = 0; + } + + debug_mask |= DEBUG_INIT; + if (debug_mask == DEBUG_INIT) + return; + + fn = safe_getenv("COMERR_DEBUG_FILE"); + if (fn) + debug_f = fopen(fn, "a"); + if (!debug_f) + debug_f = fopen("/dev/tty", "a"); + if (debug_f) { + fd = fileno(debug_f); +#if defined(HAVE_FCNTL) + if (fd >= 0) { + flags = fcntl(fd, F_GETFD); + if (flags >= 0) + flags = fcntl(fd, F_SETFD, flags | FD_CLOEXEC); + if (flags < 0) { + fprintf(debug_f, "Couldn't set FD_CLOEXEC " + "on debug FILE: %s\n", strerror(errno)); + fclose(debug_f); + debug_f = NULL; + debug_mask = DEBUG_INIT; + } + } +#endif + } else + debug_mask = DEBUG_INIT; + +} + +/* + * New interface provided by krb5's com_err library + */ +errcode_t add_error_table(const struct error_table * et) +{ + struct et_list *el; + + if (!(el = (struct et_list *) malloc(sizeof(struct et_list)))) + return ENOMEM; + + if (et_list_lock() != 0) { + free(el); + return errno; + } + + el->table = et; + el->next = _et_dynamic_list; + _et_dynamic_list = el; + + init_debug(); + if (debug_mask & DEBUG_ADDREMOVE) + fprintf(debug_f, "add_error_table: %s (0x%p)\n", + error_table_name(et->base), + (const void *) et); + + et_list_unlock(); + return 0; +} + +/* + * New interface provided by krb5's com_err library + */ +errcode_t remove_error_table(const struct error_table * et) +{ + struct et_list *el; + struct et_list *el2 = 0; + + if (et_list_lock() != 0) + return ENOENT; + + el = _et_dynamic_list; + init_debug(); + while (el) { + if (el->table->base == et->base) { + if (el2) /* Not the beginning of the list */ + el2->next = el->next; + else + _et_dynamic_list = el->next; + (void) free(el); + if (debug_mask & DEBUG_ADDREMOVE) + fprintf(debug_f, + "remove_error_table: %s (0x%p)\n", + error_table_name(et->base), + (const void *) et); + et_list_unlock(); + return 0; + } + el2 = el; + el = el->next; + } + if (debug_mask & DEBUG_ADDREMOVE) + fprintf(debug_f, "remove_error_table FAILED: %s (0x%p)\n", + error_table_name(et->base), + (const void *) et); + et_list_unlock(); + return ENOENT; +} + +/* + * Variant of the interface provided by Heimdal's com_err library + */ +void +add_to_error_table(struct et_list *new_table) +{ + add_error_table(new_table->table); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libet/error_table.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libet/error_table.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,29 @@ +/* + * Copyright 1988 by the Student Information Processing Board of the + * Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose is hereby granted, provided that + * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. M.I.T. and the + * M.I.T. S.I.P.B. make no representations about the suitability of + * this software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +#ifndef _ET_H + +struct et_list { + struct et_list *next; + const struct error_table *table; +}; +extern struct et_list *_et_list, *_et_dynamic_list; + +#define ERRCODE_RANGE 8 /* # of bits to shift table number */ +#define BITS_PER_CHAR 6 /* # bits to shift per character in name */ + +extern const char *error_table_name(errcode_t num); + +#define _ET_H +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libet/et_name.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libet/et_name.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright 1987 by MIT Student Information Processing Board + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose is hereby granted, provided that + * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. M.I.T. and the + * M.I.T. S.I.P.B. make no representations about the suitability of + * this software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +#include "config.h" +#include "com_err.h" +#include "error_table.h" +#include "internal.h" + +static const char char_set[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"; + +static char buf[6]; + +const char * error_table_name(errcode_t num) +{ + int ch; + int i; + char *p; + + /* num = aa aaa abb bbb bcc ccc cdd ddd d?? ??? ??? */ + p = buf; + num >>= ERRCODE_RANGE; + /* num = ?? ??? ??? aaa aaa bbb bbb ccc ccc ddd ddd */ + num &= 077777777L; + /* num = 00 000 000 aaa aaa bbb bbb ccc ccc ddd ddd */ + for (i = 4; i >= 0; i--) { + ch = (int)((num >> BITS_PER_CHAR * i) & ((1 << BITS_PER_CHAR) - 1)); + if (ch != 0) + *p++ = char_set[ch-1]; + } + *p = '\0'; + return(buf); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libet/init_et.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libet/init_et.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,53 @@ +/* + * $Header$ + * $Source$ + * $Locker$ + * + * Copyright 1986, 1987, 1988 by MIT Information Systems and + * the MIT Student Information Processing Board. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose is hereby granted, provided that + * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. M.I.T. and the + * M.I.T. S.I.P.B. make no representations about the suitability of + * this software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +#include "config.h" +#include +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include "com_err.h" +#include "error_table.h" + +struct foobar { + struct et_list etl; + struct error_table et; +}; + +extern struct et_list * _et_dynamic_list; + +int init_error_table(const char * const *msgs, long base, int count) +{ + struct foobar * new_et; + + if (!base || !count || !msgs) + return 0; + + new_et = (struct foobar *) malloc(sizeof(struct foobar)); + if (!new_et) + return ENOMEM; /* oops */ + new_et->etl.table = &new_et->et; + new_et->et.msgs = msgs; + new_et->et.base = base; + new_et->et.n_msgs= count; + + new_et->etl.next = _et_dynamic_list; + _et_dynamic_list = &new_et->etl; + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libet/internal.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libet/internal.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,19 @@ +/* + * internal include file for com_err package + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose is hereby granted, provided that + * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. M.I.T. and the + * M.I.T. S.I.P.B. make no representations about the suitability of + * this software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +#include + +#ifdef NEED_SYS_ERRLIST +extern char const * const sys_errlist[]; +extern const int sys_nerr; +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libet/vfprintf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libet/vfprintf.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)vfprintf.c 5.2 (Berkeley) 6/27/88"; +#endif /* LIBC_SCCS and not lint */ + +#include "config.h" +#if !HAVE_VPRINTF && HAVE_DOPRNT +#include +#include + +int +vfprintf(iop, fmt, ap) + FILE *iop; + char *fmt; + va_list ap; +{ + int len; + char localbuf[BUFSIZ]; + + if (iop->_flag & _IONBF) { + iop->_flag &= ~_IONBF; + iop->_ptr = iop->_base = localbuf; + len = _doprnt(fmt, ap, iop); + (void) fflush(iop); + iop->_flag |= _IONBF; + iop->_base = NULL; + iop->_bufsiz = 0; + iop->_cnt = 0; + } else + len = _doprnt(fmt, ap, iop); + + return (ferror(iop) ? EOF : len); +} +#endif /* !HAVE_VPRINTF */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,107 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../../.. + +TARGET = libext2fs.a libext2fs.so +PC_FILENAME = libext2fs + +# NOTE: Removed atexit.c, but the linking problem with a hidden symbol in uclibc +# NOTE: really needs fixing. On x86, there doesn't seem to be a problem with the +# NOTE: symbol provided by libuc_c_nonshared.p.a, but on MIPS the linker does +# NOTE: not want to perform the link. + +SRC_C = \ + alloc.c \ + alloc_sb.c \ + alloc_stats.c \ + alloc_tables.c \ + badblocks.c \ + bb_compat.c \ + bb_inode.c \ + bitmaps.c \ + bitops.c \ + blkmap64_ba.c \ + blkmap64_rb.c \ + blknum.c \ + block.c \ + bmap.c \ + check_desc.c \ + closefs.c \ + crc16.c \ + crc32c.c \ + csum.c \ + dblist.c \ + dblist_dir.c \ + digest_encode.c \ + dirblock.c \ + dirhash.c \ + dir_iterate.c \ + dupfs.c \ + expanddir.c \ + ext_attr.c \ + extent.c \ + fallocate.c \ + fileio.c \ + finddev.c \ + flushb.c \ + freefs.c \ + gen_bitmap64.c \ + gen_bitmap.c \ + get_num_dirs.c \ + get_pathname.c \ + getsectsize.c \ + getsize.c \ + hashmap.c \ + i_block.c \ + ind_block.c \ + initialize.c \ + inline.c \ + inline_data.c \ + inode.c \ + inode_io.c \ + io_manager.c \ + ismounted.c \ + link.c \ + llseek.c \ + lookup.c \ + mkdir.c \ + mkjournal.c \ + mmp.c \ + namei.c \ + native.c \ + newdir.c \ + openfs.c \ + progress.c \ + punch.c \ + rbtree.c \ + read_bb.c \ + read_bb_file.c \ + res_gdt.c \ + rw_bitmaps.c \ + sha256.c \ + sha512.c \ + symlink.c \ + unix_io.c \ + unlink.c \ + valid_blk.c \ + version.c \ + write_bb_file.c + +#$(TARGET): gen_crc32ctable + +#gen_crc32ctable: gen_crc32ctable.o + +#crc32c_table.h: gen_crc32ctable +# ./gen_crc32ctable > crc32c_table.h + +#crc32c.c: crc32c_table.h + +REQUIRES_LIBS = libet libe2p + +PRIVATE_INCDIR += \ + $(PKGDIR)/lib $(PKGDIR)/lib/libext2fs \ + $(PKGDIR)/include/libe2p $(PKGDIR)/include/libet \ + $(PKGDIR)/include/libext2fs/ext2fs + +CONTRIB_INCDIR = libext2fs + +include $(L4DIR)/mk/lib.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/alloc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/alloc.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,554 @@ +/* + * alloc.c --- allocate new inodes, blocks for ext2fs + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +#undef DEBUG + +#ifdef DEBUG +# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) +#else +# define dbg_printf(f, a...) +#endif + +/* + * Clear the uninit block bitmap flag if necessary + */ +void ext2fs_clear_block_uninit(ext2_filsys fs, dgrp_t group) +{ + if (group >= fs->group_desc_count || + !ext2fs_has_group_desc_csum(fs) || + !(ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT))) + return; + + /* uninit block bitmaps are now initialized in read_bitmaps() */ + + ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); + ext2fs_group_desc_csum_set(fs, group); + ext2fs_mark_super_dirty(fs); + ext2fs_mark_bb_dirty(fs); +} + +/* + * Check for uninit inode bitmaps and deal with them appropriately + */ +static void check_inode_uninit(ext2_filsys fs, ext2fs_inode_bitmap map, + dgrp_t group) +{ + ext2_ino_t i, ino; + + if (group >= fs->group_desc_count || + !ext2fs_has_group_desc_csum(fs) || + !(ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT))) + return; + + ino = (group * fs->super->s_inodes_per_group) + 1; + for (i=0; i < fs->super->s_inodes_per_group; i++, ino++) + ext2fs_fast_unmark_inode_bitmap2(map, ino); + + ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT); + /* Mimics what the kernel does */ + ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); + ext2fs_group_desc_csum_set(fs, group); + ext2fs_mark_ib_dirty(fs); + ext2fs_mark_super_dirty(fs); +} + +/* + * Right now, just search forward from the parent directory's block + * group to find the next free inode. + * + * Should have a special policy for directories. + */ +errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, + int mode EXT2FS_ATTR((unused)), + ext2fs_inode_bitmap map, ext2_ino_t *ret) +{ + ext2_ino_t start_inode = 0; + ext2_ino_t i, ino_in_group, upto, first_zero; + errcode_t retval; + dgrp_t group; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!map) + map = fs->inode_map; + if (!map) + return EXT2_ET_NO_INODE_BITMAP; + + if (dir > 0) { + group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super); + start_inode = (group * EXT2_INODES_PER_GROUP(fs->super)) + 1; + } + if (start_inode < EXT2_FIRST_INODE(fs->super)) + start_inode = EXT2_FIRST_INODE(fs->super); + if (start_inode > fs->super->s_inodes_count) + return EXT2_ET_INODE_ALLOC_FAIL; + i = start_inode; + do { + ino_in_group = (i - 1) % EXT2_INODES_PER_GROUP(fs->super); + group = (i - 1) / EXT2_INODES_PER_GROUP(fs->super); + + check_inode_uninit(fs, map, group); + upto = i + (EXT2_INODES_PER_GROUP(fs->super) - ino_in_group); + if (i < start_inode && upto >= start_inode) + upto = start_inode - 1; + if (upto > fs->super->s_inodes_count) + upto = fs->super->s_inodes_count; + + retval = ext2fs_find_first_zero_inode_bitmap2(map, i, upto, + &first_zero); + if (retval == 0) { + i = first_zero; + break; + } + if (retval != ENOENT) + return EXT2_ET_INODE_ALLOC_FAIL; + i = upto + 1; + if (i > fs->super->s_inodes_count) + i = EXT2_FIRST_INODE(fs->super); + } while (i != start_inode); + + if (ext2fs_test_inode_bitmap2(map, i)) + return EXT2_ET_INODE_ALLOC_FAIL; + *ret = i; + return 0; +} + +/* + * Stupid algorithm --- we now just search forward starting from the + * goal. Should put in a smarter one someday.... + */ +errcode_t ext2fs_new_block3(ext2_filsys fs, blk64_t goal, + ext2fs_block_bitmap map, blk64_t *ret, + struct blk_alloc_ctx *ctx) +{ + errcode_t retval; + blk64_t b = 0; + errcode_t (*gab)(ext2_filsys fs, blk64_t goal, blk64_t *ret); + errcode_t (*gab2)(ext2_filsys, blk64_t, blk64_t *, + struct blk_alloc_ctx *); + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!map) { + /* + * In case there are clients out there whose get_alloc_block + * handlers call ext2fs_new_block2 with a NULL block map, + * temporarily swap out the function pointer so that we don't + * end up in an infinite loop. + */ + if (fs->get_alloc_block2) { + gab2 = fs->get_alloc_block2; + fs->get_alloc_block2 = NULL; + retval = gab2(fs, goal, &b, ctx); + fs->get_alloc_block2 = gab2; + goto allocated; + } else if (fs->get_alloc_block) { + gab = fs->get_alloc_block; + fs->get_alloc_block = NULL; + retval = gab(fs, goal, &b); + fs->get_alloc_block = gab; + goto allocated; + } + } + if (!map) + map = fs->block_map; + if (!map) + return EXT2_ET_NO_BLOCK_BITMAP; + if (!goal || (goal >= ext2fs_blocks_count(fs->super))) + goal = fs->super->s_first_data_block; + goal &= ~EXT2FS_CLUSTER_MASK(fs); + + retval = ext2fs_find_first_zero_block_bitmap2(map, + goal, ext2fs_blocks_count(fs->super) - 1, &b); + if ((retval == ENOENT) && (goal != fs->super->s_first_data_block)) + retval = ext2fs_find_first_zero_block_bitmap2(map, + fs->super->s_first_data_block, goal - 1, &b); +allocated: + if (retval == ENOENT) + return EXT2_ET_BLOCK_ALLOC_FAIL; + if (retval) + return retval; + + ext2fs_clear_block_uninit(fs, ext2fs_group_of_blk2(fs, b)); + *ret = b; + return 0; +} + +errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal, + ext2fs_block_bitmap map, blk64_t *ret) +{ + return ext2fs_new_block3(fs, goal, map, ret, NULL); +} + +errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal, + ext2fs_block_bitmap map, blk_t *ret) +{ + errcode_t retval; + blk64_t val; + retval = ext2fs_new_block2(fs, goal, map, &val); + if (!retval) + *ret = (blk_t) val; + return retval; +} + +/* + * This function zeros out the allocated block, and updates all of the + * appropriate filesystem records. + */ +errcode_t ext2fs_alloc_block3(ext2_filsys fs, blk64_t goal, char *block_buf, + blk64_t *ret, struct blk_alloc_ctx *ctx) +{ + errcode_t retval; + blk64_t block; + + if (fs->get_alloc_block2) { + retval = (fs->get_alloc_block2)(fs, goal, &block, ctx); + if (retval) + goto fail; + } else if (fs->get_alloc_block) { + retval = (fs->get_alloc_block)(fs, goal, &block); + if (retval) + goto fail; + } else { + if (!fs->block_map) { + retval = ext2fs_read_block_bitmap(fs); + if (retval) + goto fail; + } + + retval = ext2fs_new_block3(fs, goal, 0, &block, ctx); + if (retval) + goto fail; + } + + if (block_buf) { + memset(block_buf, 0, fs->blocksize); + retval = io_channel_write_blk64(fs->io, block, 1, block_buf); + } else + retval = ext2fs_zero_blocks2(fs, block, 1, NULL, NULL); + if (retval) + goto fail; + + ext2fs_block_alloc_stats2(fs, block, +1); + *ret = block; + +fail: + return retval; +} + +errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal, + char *block_buf, blk64_t *ret) +{ + return ext2fs_alloc_block3(fs, goal, block_buf, ret, NULL); +} + +errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal, + char *block_buf, blk_t *ret) +{ + errcode_t retval; + blk64_t ret64, goal64 = goal; + retval = ext2fs_alloc_block3(fs, goal64, block_buf, &ret64, NULL); + if (!retval) + *ret = (blk_t)ret64; + return retval; +} + +errcode_t ext2fs_get_free_blocks2(ext2_filsys fs, blk64_t start, blk64_t finish, + int num, ext2fs_block_bitmap map, blk64_t *ret) +{ + blk64_t b = start; + int c_ratio; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!map) + map = fs->block_map; + if (!map) + return EXT2_ET_NO_BLOCK_BITMAP; + if (!b) + b = fs->super->s_first_data_block; + if (!finish) + finish = start; + if (!num) + num = 1; + c_ratio = 1 << ext2fs_get_bitmap_granularity(map); + b &= ~(c_ratio - 1); + finish &= ~(c_ratio -1); + do { + if (b + num - 1 >= ext2fs_blocks_count(fs->super)) { + if (finish > start) + return EXT2_ET_BLOCK_ALLOC_FAIL; + b = fs->super->s_first_data_block; + } + if (ext2fs_fast_test_block_bitmap_range2(map, b, num)) { + *ret = b; + return 0; + } + b += c_ratio; + } while (b != finish); + return EXT2_ET_BLOCK_ALLOC_FAIL; +} + +errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish, + int num, ext2fs_block_bitmap map, blk_t *ret) +{ + errcode_t retval; + blk64_t val; + retval = ext2fs_get_free_blocks2(fs, start, finish, num, map, &val); + if(!retval) + *ret = (blk_t) val; + return retval; +} + +void ext2fs_set_alloc_block_callback(ext2_filsys fs, + errcode_t (*func)(ext2_filsys fs, + blk64_t goal, + blk64_t *ret), + errcode_t (**old)(ext2_filsys fs, + blk64_t goal, + blk64_t *ret)) +{ + if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) + return; + + if (old) + *old = fs->get_alloc_block; + + fs->get_alloc_block = func; +} + +blk64_t ext2fs_find_inode_goal(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t lblk) +{ + dgrp_t group; + __u8 log_flex; + struct ext2fs_extent extent; + ext2_extent_handle_t handle = NULL; + errcode_t err; + + /* Make sure data stored in inode->i_block is neither fast symlink nor + * inline data. + */ + if (inode == NULL || ext2fs_is_fast_symlink(inode) || + inode->i_flags & EXT4_INLINE_DATA_FL) + goto no_blocks; + + if (inode->i_flags & EXT4_EXTENTS_FL) { + err = ext2fs_extent_open2(fs, ino, inode, &handle); + if (err) + goto no_blocks; + err = ext2fs_extent_goto2(handle, 0, lblk); + if (err) + goto no_blocks; + err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); + if (err) + goto no_blocks; + ext2fs_extent_free(handle); + return extent.e_pblk + (lblk - extent.e_lblk); + } + + /* block mapped file; see if block zero is mapped? */ + if (inode->i_block[0]) + return inode->i_block[0]; + +no_blocks: + ext2fs_extent_free(handle); + log_flex = fs->super->s_log_groups_per_flex; + group = ext2fs_group_of_ino(fs, ino); + if (log_flex) + group = group & ~((1 << (log_flex)) - 1); + return ext2fs_group_first_block2(fs, group); +} + +/* + * Starting at _goal_, scan around the filesystem to find a run of free blocks + * that's at least _len_ blocks long. Possible flags: + * - EXT2_NEWRANGE_EXACT_GOAL: The range of blocks must start at _goal_. + * - EXT2_NEWRANGE_MIN_LENGTH: do not return a allocation shorter than _len_. + * - EXT2_NEWRANGE_ZERO_BLOCKS: Zero blocks pblk to pblk+plen before returning. + * + * The starting block is returned in _pblk_ and the length is returned via + * _plen_. The blocks are not marked in the bitmap; the caller must mark + * however much of the returned run they actually use, hopefully via + * ext2fs_block_alloc_stats_range(). + * + * This function can return a range that is longer than what was requested. + */ +errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk, + blk64_t *plen) +{ + errcode_t retval; + blk64_t start, end, b; + int looped = 0; + blk64_t max_blocks = ext2fs_blocks_count(fs->super); + errcode_t (*nrf)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen); + + dbg_printf("%s: flags=0x%x goal=%llu len=%llu\n", __func__, flags, + goal, len); + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + if (len == 0 || (flags & ~EXT2_NEWRANGE_ALL_FLAGS)) + return EXT2_ET_INVALID_ARGUMENT; + + if (!map && fs->new_range) { + /* + * In case there are clients out there whose new_range + * handlers call ext2fs_new_range with a NULL block map, + * temporarily swap out the function pointer so that we don't + * end up in an infinite loop. + */ + nrf = fs->new_range; + fs->new_range = NULL; + retval = nrf(fs, flags, goal, len, pblk, plen); + fs->new_range = nrf; + if (retval) + return retval; + start = *pblk; + end = *pblk + *plen; + goto allocated; + } + if (!map) + map = fs->block_map; + if (!map) + return EXT2_ET_NO_BLOCK_BITMAP; + if (!goal || goal >= ext2fs_blocks_count(fs->super)) + goal = fs->super->s_first_data_block; + + start = goal; + while (!looped || start <= goal) { + retval = ext2fs_find_first_zero_block_bitmap2(map, start, + max_blocks - 1, + &start); + if (retval == ENOENT) { + /* + * If there are no free blocks beyond the starting + * point, try scanning the whole filesystem, unless the + * user told us only to allocate from _goal_, or if + * we're already scanning the whole filesystem. + */ + if (flags & EXT2_NEWRANGE_FIXED_GOAL || + start == fs->super->s_first_data_block) + goto fail; + start = fs->super->s_first_data_block; + continue; + } else if (retval) + goto errout; + + if (flags & EXT2_NEWRANGE_FIXED_GOAL && start != goal) + goto fail; + + b = min(start + len - 1, max_blocks - 1); + retval = ext2fs_find_first_set_block_bitmap2(map, start, b, + &end); + if (retval == ENOENT) + end = b + 1; + else if (retval) + goto errout; + + if (!(flags & EXT2_NEWRANGE_MIN_LENGTH) || + (end - start) >= len) { + /* Success! */ + *pblk = start; + *plen = end - start; + dbg_printf("%s: new_range goal=%llu--%llu " + "blk=%llu--%llu %llu\n", + __func__, goal, goal + len - 1, + *pblk, *pblk + *plen - 1, *plen); +allocated: + for (b = start; b < end; + b += fs->super->s_blocks_per_group) + ext2fs_clear_block_uninit(fs, + ext2fs_group_of_blk2(fs, b)); + return 0; + } + + if (flags & EXT2_NEWRANGE_FIXED_GOAL) + goto fail; + start = end; + if (start >= max_blocks) { + if (looped) + goto fail; + looped = 1; + start = fs->super->s_first_data_block; + } + } + +fail: + retval = EXT2_ET_BLOCK_ALLOC_FAIL; +errout: + return retval; +} + +void ext2fs_set_new_range_callback(ext2_filsys fs, + errcode_t (*func)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen), + errcode_t (**old)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen)) +{ + if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) + return; + + if (old) + *old = fs->new_range; + + fs->new_range = func; +} + +errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal, + blk_t len, blk64_t *ret) +{ + int newr_flags = EXT2_NEWRANGE_MIN_LENGTH; + errcode_t retval; + blk64_t plen; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + if (len == 0 || (flags & ~EXT2_ALLOCRANGE_ALL_FLAGS)) + return EXT2_ET_INVALID_ARGUMENT; + + if (flags & EXT2_ALLOCRANGE_FIXED_GOAL) + newr_flags |= EXT2_NEWRANGE_FIXED_GOAL; + + retval = ext2fs_new_range(fs, newr_flags, goal, len, NULL, ret, &plen); + if (retval) + return retval; + + if (plen < len) + return EXT2_ET_BLOCK_ALLOC_FAIL; + + if (flags & EXT2_ALLOCRANGE_ZERO_BLOCKS) { + retval = ext2fs_zero_blocks2(fs, *ret, len, NULL, NULL); + if (retval) + return retval; + } + + ext2fs_block_alloc_stats_range(fs, *ret, len, +1); + return retval; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/alloc_sb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/alloc_sb.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,81 @@ +/* + * alloc_sb.c --- Allocate the superblock and block group descriptors for a + * newly initialized filesystem. Used by mke2fs when initializing a filesystem + * + * Copyright (C) 1994, 1995, 1996, 2003 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +/* + * This function reserves the superblock and block group descriptors + * for a given block group. It currently returns the number of free + * blocks assuming that inode table and allocation bitmaps will be in + * the group. This is not necessarily the case when the flex_bg + * feature is enabled, so callers should take care! It was only + * really intended for use by mke2fs, and even there it's not that + * useful. In the future, when we redo this function for 64-bit block + * numbers, we should probably return the number of blocks used by the + * super block and group descriptors instead. + * + * See also the comment for ext2fs_super_and_bgd_loc() + */ +int ext2fs_reserve_super_and_bgd(ext2_filsys fs, + dgrp_t group, + ext2fs_block_bitmap bmap) +{ + blk64_t super_blk, old_desc_blk, new_desc_blk; + blk_t used_blks; + int old_desc_blocks, num_blocks; + + ext2fs_super_and_bgd_loc2(fs, group, &super_blk, + &old_desc_blk, &new_desc_blk, &used_blks); + + if (ext2fs_has_feature_meta_bg(fs->super)) + old_desc_blocks = fs->super->s_first_meta_bg; + else + old_desc_blocks = + fs->desc_blocks + fs->super->s_reserved_gdt_blocks; + + if (super_blk || (group == 0)) + ext2fs_mark_block_bitmap2(bmap, super_blk); + if ((group == 0) && (fs->blocksize == 1024) && + EXT2FS_CLUSTER_RATIO(fs) > 1) + ext2fs_mark_block_bitmap2(bmap, 0); + + if (old_desc_blk) { + num_blocks = old_desc_blocks; + if (old_desc_blk + num_blocks >= ext2fs_blocks_count(fs->super)) + num_blocks = ext2fs_blocks_count(fs->super) - + old_desc_blk; + ext2fs_mark_block_bitmap_range2(bmap, old_desc_blk, num_blocks); + } + if (new_desc_blk) + ext2fs_mark_block_bitmap2(bmap, new_desc_blk); + + num_blocks = ext2fs_group_blocks_count(fs, group); + num_blocks -= 2 + fs->inode_blocks_per_group + used_blks; + + return num_blocks ; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/alloc_stats.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/alloc_stats.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,164 @@ +/* + * alloc_stats.c --- Update allocation statistics for ext2fs + * + * Copyright (C) 2001 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include + +#include "ext2_fs.h" +#include "ext2fs.h" + +void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino, + int inuse, int isdir) +{ + int group = ext2fs_group_of_ino(fs, ino); + + if (ino > fs->super->s_inodes_count) { +#ifndef OMIT_COM_ERR + com_err("ext2fs_inode_alloc_stats2", 0, + "Illegal inode number: %lu", (unsigned long) ino); +#endif + return; + } + if (inuse > 0) + ext2fs_mark_inode_bitmap2(fs->inode_map, ino); + else + ext2fs_unmark_inode_bitmap2(fs->inode_map, ino); + ext2fs_bg_free_inodes_count_set(fs, group, ext2fs_bg_free_inodes_count(fs, group) - inuse); + if (isdir) + ext2fs_bg_used_dirs_count_set(fs, group, ext2fs_bg_used_dirs_count(fs, group) + inuse); + + /* We don't strictly need to be clearing the uninit flag if inuse < 0 + * (i.e. freeing inodes) but it also means something is bad. */ + ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT); + if (ext2fs_has_group_desc_csum(fs)) { + ext2_ino_t first_unused_inode = fs->super->s_inodes_per_group - + ext2fs_bg_itable_unused(fs, group) + + group * fs->super->s_inodes_per_group + 1; + + if (ino >= first_unused_inode) + ext2fs_bg_itable_unused_set(fs, group, group * fs->super->s_inodes_per_group + fs->super->s_inodes_per_group - ino); + ext2fs_group_desc_csum_set(fs, group); + } + + fs->super->s_free_inodes_count -= inuse; + ext2fs_mark_super_dirty(fs); + ext2fs_mark_ib_dirty(fs); +} + +void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse) +{ + ext2fs_inode_alloc_stats2(fs, ino, inuse, 0); +} + +void ext2fs_block_alloc_stats2(ext2_filsys fs, blk64_t blk, int inuse) +{ + int group = ext2fs_group_of_blk2(fs, blk); + + if (blk >= ext2fs_blocks_count(fs->super)) { +#ifndef OMIT_COM_ERR + com_err("ext2fs_block_alloc_stats", 0, + "Illegal block number: %lu", (unsigned long) blk); +#endif + return; + } + if (inuse > 0) + ext2fs_mark_block_bitmap2(fs->block_map, blk); + else + ext2fs_unmark_block_bitmap2(fs->block_map, blk); + ext2fs_bg_free_blocks_count_set(fs, group, ext2fs_bg_free_blocks_count(fs, group) - inuse); + ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); + ext2fs_group_desc_csum_set(fs, group); + + ext2fs_free_blocks_count_add(fs->super, + -inuse * (blk64_t) EXT2FS_CLUSTER_RATIO(fs)); + ext2fs_mark_super_dirty(fs); + ext2fs_mark_bb_dirty(fs); + if (fs->block_alloc_stats) + (fs->block_alloc_stats)(fs, (blk64_t) blk, inuse); +} + +void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse) +{ + ext2fs_block_alloc_stats2(fs, blk, inuse); +} + +void ext2fs_set_block_alloc_stats_callback(ext2_filsys fs, + void (*func)(ext2_filsys fs, + blk64_t blk, + int inuse), + void (**old)(ext2_filsys fs, + blk64_t blk, + int inuse)) +{ + if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) + return; + if (old) + *old = fs->block_alloc_stats; + + fs->block_alloc_stats = func; +} + +void ext2fs_block_alloc_stats_range(ext2_filsys fs, blk64_t blk, + blk_t num, int inuse) +{ +#ifndef OMIT_COM_ERR + if (blk + num > ext2fs_blocks_count(fs->super)) { + com_err("ext2fs_block_alloc_stats_range", 0, + "Illegal block range: %llu (%u) ", + (unsigned long long) blk, num); + return; + } +#endif + if (inuse == 0) + return; + if (inuse > 0) { + ext2fs_mark_block_bitmap_range2(fs->block_map, blk, num); + inuse = 1; + } else { + ext2fs_unmark_block_bitmap_range2(fs->block_map, blk, num); + inuse = -1; + } + while (num) { + int group = ext2fs_group_of_blk2(fs, blk); + blk64_t last_blk = ext2fs_group_last_block2(fs, group); + blk64_t n = num; + + if (blk + num > last_blk) + n = last_blk - blk + 1; + + ext2fs_bg_free_blocks_count_set(fs, group, + ext2fs_bg_free_blocks_count(fs, group) - + inuse*n/EXT2FS_CLUSTER_RATIO(fs)); + ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); + ext2fs_group_desc_csum_set(fs, group); + ext2fs_free_blocks_count_add(fs->super, -inuse * (blk64_t) n); + blk += n; + num -= n; + } + ext2fs_mark_super_dirty(fs); + ext2fs_mark_bb_dirty(fs); + if (fs->block_alloc_stats_range) + (fs->block_alloc_stats_range)(fs, blk, num, inuse); +} + +void ext2fs_set_block_alloc_stats_range_callback(ext2_filsys fs, + void (*func)(ext2_filsys fs, blk64_t blk, + blk_t num, int inuse), + void (**old)(ext2_filsys fs, blk64_t blk, + blk_t num, int inuse)) +{ + if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) + return; + if (old) + *old = fs->block_alloc_stats_range; + + fs->block_alloc_stats_range = func; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/alloc_tables.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/alloc_tables.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,278 @@ +/* + * alloc_tables.c --- Allocate tables for a newly initialized + * filesystem. Used by mke2fs when initializing a filesystem + * + * Copyright (C) 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +/* + * This routine searches for free blocks that can allocate a full + * group of bitmaps or inode tables for a flexbg group. Returns the + * block number with a correct offset were the bitmaps and inode + * tables can be allocated continuously and in order. + */ +static blk64_t flexbg_offset(ext2_filsys fs, dgrp_t group, blk64_t start_blk, + ext2fs_block_bitmap bmap, int rem_grp, + int elem_size) +{ + int flexbg, flexbg_size, size; + blk64_t last_blk, first_free = 0; + dgrp_t last_grp; + + flexbg_size = 1 << fs->super->s_log_groups_per_flex; + flexbg = group / flexbg_size; + size = rem_grp * elem_size; + + if (size > (int) (fs->super->s_blocks_per_group / 4)) + size = (int) fs->super->s_blocks_per_group / 4; + + /* + * Don't do a long search if the previous block search is still valid, + * but skip minor obstructions such as group descriptor backups. + */ + if (start_blk && start_blk < ext2fs_blocks_count(fs->super) && + ext2fs_get_free_blocks2(fs, start_blk, start_blk + size, elem_size, + bmap, &first_free) == 0) + return first_free; + + start_blk = ext2fs_group_first_block2(fs, flexbg_size * flexbg); + last_grp = group | (flexbg_size - 1); + if (last_grp > fs->group_desc_count-1) + last_grp = fs->group_desc_count-1; + last_blk = ext2fs_group_last_block2(fs, last_grp); + + /* Find the first available block */ + if (ext2fs_get_free_blocks2(fs, start_blk, last_blk, size, + bmap, &first_free) == 0) + return first_free; + + if (ext2fs_get_free_blocks2(fs, start_blk, last_blk, elem_size, + bmap, &first_free) == 0) + return first_free; + + if (ext2fs_get_free_blocks2(fs, 0, last_blk, elem_size, bmap, + &first_free) == 0) + return first_free; + + return first_free; +} + +errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, + ext2fs_block_bitmap bmap) +{ + errcode_t retval; + blk64_t group_blk, start_blk, last_blk, new_blk; + dgrp_t last_grp = 0; + int rem_grps = 0, flexbg_size = 0, table_offset = 0; + + group_blk = ext2fs_group_first_block2(fs, group); + last_blk = ext2fs_group_last_block2(fs, group); + + if (!bmap) + bmap = fs->block_map; + + if (ext2fs_has_feature_flex_bg(fs->super) && + fs->super->s_log_groups_per_flex) { + flexbg_size = 1 << fs->super->s_log_groups_per_flex; + last_grp = group | (flexbg_size - 1); + if (last_grp > fs->group_desc_count-1) + last_grp = fs->group_desc_count-1; + rem_grps = last_grp - group + 1; + } + + /* + * Allocate the block and inode bitmaps, if necessary + */ + if (fs->stride && !flexbg_size) { + retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk, + 1, bmap, &start_blk); + if (retval) + return retval; + start_blk += fs->inode_blocks_per_group; + start_blk += ((fs->stride * group) % + (last_blk - start_blk + 1)); + if (start_blk >= last_blk) + start_blk = group_blk; + } else + start_blk = group_blk; + + if (flexbg_size) { + blk64_t prev_block = 0; + + table_offset = flexbg_size; + if (group % flexbg_size) + prev_block = ext2fs_block_bitmap_loc(fs, group - 1) + 1; + else if (last_grp == fs->group_desc_count-1) { + /* + * If we are allocating for the last flex_bg + * keep the metadata tables contiguous + */ + table_offset = last_grp & (flexbg_size - 1); + if (table_offset == 0) + table_offset = flexbg_size; + else + table_offset++; + } + /* FIXME: Take backup group descriptor blocks into account + * if the flexbg allocations will grow to overlap them... */ + start_blk = flexbg_offset(fs, group, prev_block, bmap, + rem_grps, 1); + last_blk = ext2fs_group_last_block2(fs, last_grp); + } + + if (!ext2fs_block_bitmap_loc(fs, group)) { + retval = ext2fs_get_free_blocks2(fs, start_blk, last_blk, + 1, bmap, &new_blk); + if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) + retval = ext2fs_get_free_blocks2(fs, group_blk, + last_blk, 1, bmap, &new_blk); + if (retval) + return retval; + ext2fs_mark_block_bitmap2(bmap, new_blk); + ext2fs_block_bitmap_loc_set(fs, group, new_blk); + if (flexbg_size) { + dgrp_t gr = ext2fs_group_of_blk2(fs, new_blk); + ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1); + ext2fs_free_blocks_count_add(fs->super, -1); + ext2fs_bg_flags_clear(fs, gr, EXT2_BG_BLOCK_UNINIT); + ext2fs_group_desc_csum_set(fs, gr); + } + } + + if (flexbg_size) { + blk64_t prev_block = 0; + if (group % flexbg_size) + prev_block = ext2fs_inode_bitmap_loc(fs, group - 1) + 1; + else + prev_block = ext2fs_block_bitmap_loc(fs, group) + + table_offset; + /* FIXME: Take backup group descriptor blocks into account + * if the flexbg allocations will grow to overlap them... */ + start_blk = flexbg_offset(fs, group, prev_block, bmap, + rem_grps, 1); + last_blk = ext2fs_group_last_block2(fs, last_grp); + } + + if (!ext2fs_inode_bitmap_loc(fs, group)) { + retval = ext2fs_get_free_blocks2(fs, start_blk, last_blk, + 1, bmap, &new_blk); + if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) + retval = ext2fs_get_free_blocks2(fs, group_blk, + last_blk, 1, bmap, &new_blk); + if (retval) + return retval; + ext2fs_mark_block_bitmap2(bmap, new_blk); + ext2fs_inode_bitmap_loc_set(fs, group, new_blk); + if (flexbg_size) { + dgrp_t gr = ext2fs_group_of_blk2(fs, new_blk); + ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1); + ext2fs_free_blocks_count_add(fs->super, -1); + ext2fs_bg_flags_clear(fs, gr, EXT2_BG_BLOCK_UNINIT); + ext2fs_group_desc_csum_set(fs, gr); + } + } + + /* + * Allocate the inode table + */ + if (flexbg_size) { + blk64_t prev_block = 0; + + if (group % flexbg_size) + prev_block = ext2fs_inode_table_loc(fs, group - 1) + + fs->inode_blocks_per_group; + else + prev_block = ext2fs_inode_bitmap_loc(fs, group) + + table_offset; + + /* FIXME: Take backup group descriptor blocks into account + * if the flexbg allocations will grow to overlap them... */ + group_blk = flexbg_offset(fs, group, prev_block, bmap, + rem_grps, fs->inode_blocks_per_group); + last_blk = ext2fs_group_last_block2(fs, last_grp); + } + + if (!ext2fs_inode_table_loc(fs, group)) { + retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk, + fs->inode_blocks_per_group, + bmap, &new_blk); + if (retval) + return retval; + + ext2fs_mark_block_bitmap_range2(bmap, + new_blk, fs->inode_blocks_per_group); + if (flexbg_size) { + blk64_t num, blk; + num = fs->inode_blocks_per_group; + blk = new_blk; + while (num) { + int gr = ext2fs_group_of_blk2(fs, blk); + last_blk = ext2fs_group_last_block2(fs, gr); + blk64_t n = num; + + if (blk + num > last_blk) + n = last_blk - blk + 1; + + ext2fs_bg_free_blocks_count_set(fs, gr, + ext2fs_bg_free_blocks_count(fs, gr) - + n/EXT2FS_CLUSTER_RATIO(fs)); + ext2fs_bg_flags_clear(fs, gr, + EXT2_BG_BLOCK_UNINIT); + ext2fs_group_desc_csum_set(fs, gr); + ext2fs_free_blocks_count_add(fs->super, -n); + blk += n; + num -= n; + } + } + ext2fs_inode_table_loc_set(fs, group, new_blk); + } + ext2fs_group_desc_csum_set(fs, group); + return 0; +} + +errcode_t ext2fs_allocate_tables(ext2_filsys fs) +{ + errcode_t retval; + dgrp_t i; + struct ext2fs_numeric_progress_struct progress; + + if (fs->progress_ops && fs->progress_ops->init) + (fs->progress_ops->init)(fs, &progress, NULL, + fs->group_desc_count); + + for (i = 0; i < fs->group_desc_count; i++) { + if (fs->progress_ops && fs->progress_ops->update) + (fs->progress_ops->update)(fs, &progress, i); + retval = ext2fs_allocate_group_table(fs, i, fs->block_map); + if (retval) + return retval; + } + if (fs->progress_ops && fs->progress_ops->close) + (fs->progress_ops->close)(fs, &progress, NULL); + return 0; +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/atexit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/atexit.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,116 @@ +/* + * atexit.c --- Clean things up when we exit normally. + * + * Copyright Oracle, 2014 + * Author Darrick J. Wong + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#include "config.h" +#include + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +struct exit_data { + ext2_exit_fn func; + void *data; +}; + +static struct exit_data *items; +static size_t nr_items; + +static void handle_exit(void) +{ + struct exit_data *ed; + + for (ed = items + nr_items - 1; ed >= items; ed--) { + if (ed->func == NULL) + continue; + ed->func(ed->data); + } + + ext2fs_free_mem(&items); + nr_items = 0; +} + +/* + * Schedule a function to be called at (normal) program termination. + * If you want this to be called during a signal exit, you must capture + * the signal and call exit() yourself! + */ +errcode_t ext2fs_add_exit_fn(ext2_exit_fn func, void *data) +{ + struct exit_data *ed, *free_ed = NULL; + size_t x; + errcode_t ret; + + if (func == NULL) + return EXT2_ET_INVALID_ARGUMENT; + + for (x = 0, ed = items; x < nr_items; x++, ed++) { + if (ed->func == func && ed->data == data) + return EXT2_ET_FILE_EXISTS; + if (ed->func == NULL) + free_ed = ed; + } + + if (free_ed) { + free_ed->func = func; + free_ed->data = data; + return 0; + } + + if (nr_items == 0) { + ret = atexit(handle_exit); + if (ret) + return ret; + } + + ret = ext2fs_resize_mem(0, (nr_items + 1) * sizeof(struct exit_data), + &items); + if (ret) + return ret; + + items[nr_items].func = func; + items[nr_items].data = data; + nr_items++; + + return 0; +} + +/* Remove a function from the exit cleanup list. */ +errcode_t ext2fs_remove_exit_fn(ext2_exit_fn func, void *data) +{ + struct exit_data *ed; + size_t x; + + if (func == NULL) + return EXT2_ET_INVALID_ARGUMENT; + + for (x = 0, ed = items; x < nr_items; x++, ed++) { + if (ed->func == NULL) + return 0; + if (ed->func == func && ed->data == data) { + size_t sz = (nr_items - (x + 1)) * + sizeof(struct exit_data); + memmove(ed, ed + 1, sz); + memset(items + nr_items - 1, 0, + sizeof(struct exit_data)); + } + } + + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/badblocks.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/badblocks.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,328 @@ +/* + * badblocks.c --- routines to manipulate the bad block structure + * + * Copyright (C) 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" + +/* + * Helper function for making a badblocks list + */ +static errcode_t make_u32_list(int size, int num, __u32 *list, + ext2_u32_list *ret) +{ + ext2_u32_list bb; + errcode_t retval; + + retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_list), &bb); + if (retval) + return retval; + memset(bb, 0, sizeof(struct ext2_struct_u32_list)); + bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST; + bb->size = size ? size : 10; + bb->num = num; + retval = ext2fs_get_array(bb->size, sizeof(blk_t), &bb->list); + if (retval) { + ext2fs_free_mem(&bb); + return retval; + } + if (list) + memcpy(bb->list, list, bb->size * sizeof(blk_t)); + else + memset(bb->list, 0, bb->size * sizeof(blk_t)); + *ret = bb; + return 0; +} + + +/* + * This procedure creates an empty u32 list. + */ +errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size) +{ + return make_u32_list(size, 0, 0, ret); +} + +/* + * This procedure creates an empty badblocks list. + */ +errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size) +{ + return make_u32_list(size, 0, 0, (ext2_badblocks_list *) ret); +} + + +/* + * This procedure copies a badblocks list + */ +errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest) +{ + errcode_t retval; + + retval = make_u32_list(src->size, src->num, src->list, dest); + if (retval) + return retval; + (*dest)->badblocks_flags = src->badblocks_flags; + return 0; +} + +errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src, + ext2_badblocks_list *dest) +{ + return ext2fs_u32_copy((ext2_u32_list) src, + (ext2_u32_list *) dest); +} + +/* + * This procedure frees a badblocks list. + * + * (note: moved to closefs.c) + */ + + +/* + * This procedure adds a block to a badblocks list. + */ +errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk) +{ + errcode_t retval; + int i, j; + unsigned long old_size; + + EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST); + + if (bb->num >= bb->size) { + old_size = bb->size * sizeof(__u32); + bb->size += 100; + retval = ext2fs_resize_mem(old_size, bb->size * sizeof(__u32), + &bb->list); + if (retval) { + bb->size -= 100; + return retval; + } + } + + /* + * Add special case code for appending to the end of the list + */ + i = bb->num-1; + if ((bb->num != 0) && (bb->list[i] == blk)) + return 0; + if ((bb->num == 0) || (bb->list[i] < blk)) { + bb->list[bb->num++] = blk; + return 0; + } + + j = bb->num; + for (i=0; i < bb->num; i++) { + if (bb->list[i] == blk) + return 0; + if (bb->list[i] > blk) { + j = i; + break; + } + } + for (i=bb->num; i > j; i--) + bb->list[i] = bb->list[i-1]; + bb->list[j] = blk; + bb->num++; + return 0; +} + +errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk) +{ + return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk); +} + +/* + * This procedure finds a particular block is on a badblocks + * list. + */ +int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk) +{ + int low, high, mid; + + if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST) + return -1; + + if (bb->num == 0) + return -1; + + low = 0; + high = bb->num-1; + if (blk == bb->list[low]) + return low; + if (blk == bb->list[high]) + return high; + + while (low < high) { + mid = ((unsigned)low + (unsigned)high)/2; + if (mid == low || mid == high) + break; + if (blk == bb->list[mid]) + return mid; + if (blk < bb->list[mid]) + high = mid; + else + low = mid; + } + return -1; +} + +/* + * This procedure tests to see if a particular block is on a badblocks + * list. + */ +int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk) +{ + if (ext2fs_u32_list_find(bb, blk) < 0) + return 0; + else + return 1; +} + +int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk) +{ + return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk); +} + + +/* + * Remove a block from the badblock list + */ +int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk) +{ + int remloc, i; + + if (bb->num == 0) + return -1; + + remloc = ext2fs_u32_list_find(bb, blk); + if (remloc < 0) + return -1; + + for (i = remloc ; i < bb->num-1; i++) + bb->list[i] = bb->list[i+1]; + bb->num--; + return 0; +} + +void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk) +{ + ext2fs_u32_list_del(bb, blk); +} + +errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb, + ext2_u32_iterate *ret) +{ + ext2_u32_iterate iter; + errcode_t retval; + + EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST); + + retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_iterate), &iter); + if (retval) + return retval; + + iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE; + iter->bb = bb; + iter->ptr = 0; + *ret = iter; + return 0; +} + +errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb, + ext2_badblocks_iterate *ret) +{ + return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb, + (ext2_u32_iterate *) ret); +} + + +int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk) +{ + ext2_u32_list bb; + + if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE) + return 0; + + bb = iter->bb; + + if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST) + return 0; + + if (iter->ptr < bb->num) { + *blk = bb->list[iter->ptr++]; + return 1; + } + *blk = 0; + return 0; +} + +int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk) +{ + return ext2fs_u32_list_iterate((ext2_u32_iterate) iter, + (__u32 *) blk); +} + + +void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter) +{ + if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)) + return; + + iter->bb = 0; + ext2fs_free_mem(&iter); +} + +void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter) +{ + ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter); +} + + +int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2) +{ + EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST); + EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST); + + if (bb1->num != bb2->num) + return 0; + + if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0) + return 0; + return 1; +} + +int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2) +{ + return ext2fs_u32_list_equal((ext2_u32_list) bb1, + (ext2_u32_list) bb2); +} + +int ext2fs_u32_list_count(ext2_u32_list bb) +{ + return bb->num; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/bb_compat.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/bb_compat.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,64 @@ +/* + * bb_compat.c --- compatibility badblocks routines + * + * Copyright (C) 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" + +errcode_t badblocks_list_create(badblocks_list *ret, int size) +{ + return ext2fs_badblocks_list_create(ret, size); +} + +void badblocks_list_free(badblocks_list bb) +{ + ext2fs_badblocks_list_free(bb); +} + +errcode_t badblocks_list_add(badblocks_list bb, blk_t blk) +{ + return ext2fs_badblocks_list_add(bb, blk); +} + +int badblocks_list_test(badblocks_list bb, blk_t blk) +{ + return ext2fs_badblocks_list_test(bb, blk); +} + +errcode_t badblocks_list_iterate_begin(badblocks_list bb, + badblocks_iterate *ret) +{ + return ext2fs_badblocks_list_iterate_begin(bb, ret); +} + +int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk) +{ + return ext2fs_badblocks_list_iterate(iter, blk); +} + +void badblocks_list_iterate_end(badblocks_iterate iter) +{ + ext2fs_badblocks_list_iterate_end(iter); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/bb_inode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/bb_inode.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,270 @@ +/* + * bb_inode.c --- routines to update the bad block inode. + * + * WARNING: This routine modifies a lot of state in the filesystem; if + * this routine returns an error, the bad block inode may be in an + * inconsistent state. + * + * Copyright (C) 1994, 1995 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +struct set_badblock_record { + ext2_badblocks_iterate bb_iter; + int bad_block_count; + blk_t *ind_blocks; + int max_ind_blocks; + int ind_blocks_size; + int ind_blocks_ptr; + char *block_buf; + errcode_t err; +}; + +static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr, + e2_blkcnt_t blockcnt, + blk_t ref_block, int ref_offset, + void *priv_data); +static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr, + e2_blkcnt_t blockcnt, + blk_t ref_block, int ref_offset, + void *priv_data); + +/* + * Given a bad blocks bitmap, update the bad blocks inode to reflect + * the map. + */ +errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list) +{ + errcode_t retval; + struct set_badblock_record rec; + struct ext2_inode inode; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!fs->block_map) + return EXT2_ET_NO_BLOCK_BITMAP; + + memset(&rec, 0, sizeof(rec)); + rec.max_ind_blocks = 10; + retval = ext2fs_get_array(rec.max_ind_blocks, sizeof(blk_t), + &rec.ind_blocks); + if (retval) + return retval; + memset(rec.ind_blocks, 0, rec.max_ind_blocks * sizeof(blk_t)); + retval = ext2fs_get_mem(fs->blocksize, &rec.block_buf); + if (retval) + goto cleanup; + memset(rec.block_buf, 0, fs->blocksize); + rec.err = 0; + + /* + * First clear the old bad blocks (while saving the indirect blocks) + */ + retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, + BLOCK_FLAG_DEPTH_TRAVERSE, 0, + clear_bad_block_proc, &rec); + if (retval) + goto cleanup; + if (rec.err) { + retval = rec.err; + goto cleanup; + } + + /* + * Now set the bad blocks! + * + * First, mark the bad blocks as used. This prevents a bad + * block from being used as an indirect block for the bad + * block inode (!). + */ + if (bb_list) { + retval = ext2fs_badblocks_list_iterate_begin(bb_list, + &rec.bb_iter); + if (retval) + goto cleanup; + retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, + BLOCK_FLAG_APPEND, 0, + set_bad_block_proc, &rec); + ext2fs_badblocks_list_iterate_end(rec.bb_iter); + if (retval) + goto cleanup; + if (rec.err) { + retval = rec.err; + goto cleanup; + } + } + + /* + * Update the bad block inode's mod time and block count + * field. + */ + retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode); + if (retval) + goto cleanup; + + inode.i_atime = inode.i_mtime = fs->now ? fs->now : time(0); + if (!inode.i_ctime) + inode.i_ctime = fs->now ? fs->now : time(0); + ext2fs_iblk_set(fs, &inode, rec.bad_block_count); + retval = ext2fs_inode_size_set(fs, &inode, + rec.bad_block_count * fs->blocksize); + if (retval) + goto cleanup; + + retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode); + if (retval) + goto cleanup; + +cleanup: + ext2fs_free_mem(&rec.ind_blocks); + ext2fs_free_mem(&rec.block_buf); + return retval; +} + +/* + * Helper function for update_bb_inode() + * + * Clear the bad blocks in the bad block inode, while saving the + * indirect blocks. + */ +#ifdef __TURBOC__ + #pragma argsused +#endif +static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr, + e2_blkcnt_t blockcnt, + blk_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct set_badblock_record *rec = (struct set_badblock_record *) + priv_data; + errcode_t retval; + unsigned long old_size; + + if (!*block_nr) + return 0; + + /* + * If the block number is outrageous, clear it and ignore it. + */ + if (*block_nr >= ext2fs_blocks_count(fs->super) || + *block_nr < fs->super->s_first_data_block) { + *block_nr = 0; + return BLOCK_CHANGED; + } + + if (blockcnt < 0) { + if (rec->ind_blocks_size >= rec->max_ind_blocks) { + old_size = rec->max_ind_blocks * sizeof(blk_t); + rec->max_ind_blocks += 10; + retval = ext2fs_resize_mem(old_size, + rec->max_ind_blocks * sizeof(blk_t), + &rec->ind_blocks); + if (retval) { + rec->max_ind_blocks -= 10; + rec->err = retval; + return BLOCK_ABORT; + } + } + rec->ind_blocks[rec->ind_blocks_size++] = *block_nr; + } + + /* + * Mark the block as unused, and update accounting information + */ + ext2fs_block_alloc_stats2(fs, *block_nr, -1); + + *block_nr = 0; + return BLOCK_CHANGED; +} + + +/* + * Helper function for update_bb_inode() + * + * Set the block list in the bad block inode, using the supplied bitmap. + */ +#ifdef __TURBOC__ + #pragma argsused +#endif +static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr, + e2_blkcnt_t blockcnt, + blk_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct set_badblock_record *rec = (struct set_badblock_record *) + priv_data; + errcode_t retval; + blk_t blk; + + if (blockcnt >= 0) { + /* + * Get the next bad block. + */ + if (!ext2fs_badblocks_list_iterate(rec->bb_iter, &blk)) + return BLOCK_ABORT; + rec->bad_block_count++; + } else { + /* + * An indirect block; fetch a block from the + * previously used indirect block list. The block + * most be not marked as used; if so, get another one. + * If we run out of reserved indirect blocks, allocate + * a new one. + */ + retry: + if (rec->ind_blocks_ptr < rec->ind_blocks_size) { + blk = rec->ind_blocks[rec->ind_blocks_ptr++]; + if (ext2fs_test_block_bitmap2(fs->block_map, blk)) + goto retry; + } else { + retval = ext2fs_new_block(fs, 0, 0, &blk); + if (retval) { + rec->err = retval; + return BLOCK_ABORT; + } + } + retval = io_channel_write_blk64(fs->io, blk, 1, rec->block_buf); + if (retval) { + rec->err = retval; + return BLOCK_ABORT; + } + } + + /* + * Update block counts + */ + ext2fs_block_alloc_stats2(fs, blk, +1); + + *block_nr = blk; + return BLOCK_CHANGED; +} + + + + + + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/bitmaps.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/bitmaps.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,308 @@ +/* + * bitmaps.c --- routines to read, write, and manipulate the inode and + * block bitmaps. + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" +#include "bmap64.h" + +void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap) +{ + ext2fs_free_generic_bmap(bitmap); +} + +void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap) +{ + ext2fs_free_generic_bmap(bitmap); +} + +errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap *dest) +{ + return (ext2fs_copy_generic_bmap(src, dest)); +} +void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map) +{ + ext2fs_set_generic_bmap_padding(map); +} + +errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_inode_bitmap *ret) +{ + __u64 start, end, real_end; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + fs->write_bitmaps = ext2fs_write_bitmaps; + + start = 1; + end = fs->super->s_inodes_count; + real_end = (EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count); + + /* Are we permitted to use new-style bitmaps? */ + if (fs->flags & EXT2_FLAG_64BITS) + return (ext2fs_alloc_generic_bmap(fs, + EXT2_ET_MAGIC_INODE_BITMAP64, + fs->default_bitmap_type, + start, end, real_end, descr, ret)); + + /* Otherwise, check to see if the file system is small enough + * to use old-style 32-bit bitmaps */ + if ((end > ~0U) || (real_end > ~0U)) + return EXT2_ET_CANT_USE_LEGACY_BITMAPS; + + return (ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_INODE_BITMAP, fs, + start, end, real_end, + descr, 0, + (ext2fs_generic_bitmap *) ret)); +} + +errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_block_bitmap *ret) +{ + __u64 start, end, real_end; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + fs->write_bitmaps = ext2fs_write_bitmaps; + + start = EXT2FS_B2C(fs, fs->super->s_first_data_block); + end = EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super)-1); + real_end = ((__u64) EXT2_CLUSTERS_PER_GROUP(fs->super) + * (__u64) fs->group_desc_count)-1 + start; + + if (fs->flags & EXT2_FLAG_64BITS) + return (ext2fs_alloc_generic_bmap(fs, + EXT2_ET_MAGIC_BLOCK_BITMAP64, + fs->default_bitmap_type, + start, end, real_end, descr, ret)); + + if ((end > ~0U) || (real_end > ~0U)) + return EXT2_ET_CANT_USE_LEGACY_BITMAPS; + + return (ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, fs, + start, end, real_end, + descr, 0, + (ext2fs_generic_bitmap *) ret)); +} + +/* + * ext2fs_allocate_block_bitmap() really allocates a per-cluster + * bitmap for backwards compatibility. This function allocates a + * block bitmap which is truly per-block, even if clusters/bigalloc + * are enabled. mke2fs and e2fsck need this for tracking the + * allocation of the file system metadata blocks. + */ +errcode_t ext2fs_allocate_subcluster_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_block_bitmap *ret) +{ + __u64 start, end, real_end; + ext2fs_generic_bitmap bmap; + errcode_t retval; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + fs->write_bitmaps = ext2fs_write_bitmaps; + + if (!fs->cluster_ratio_bits) + return ext2fs_allocate_block_bitmap(fs, descr, ret); + + if ((fs->flags & EXT2_FLAG_64BITS) == 0) + return EXT2_ET_CANT_USE_LEGACY_BITMAPS; + + start = fs->super->s_first_data_block; + end = ext2fs_blocks_count(fs->super)-1; + real_end = ((__u64) EXT2_BLOCKS_PER_GROUP(fs->super) + * (__u64) fs->group_desc_count)-1 + start; + + retval = ext2fs_alloc_generic_bmap(fs, EXT2_ET_MAGIC_BLOCK_BITMAP64, + fs->default_bitmap_type, start, + end, real_end, descr, &bmap); + if (retval) + return retval; + bmap->cluster_bits = 0; + *ret = bmap; + return 0; +} + +int ext2fs_get_bitmap_granularity(ext2fs_block_bitmap bitmap) +{ + ext2fs_generic_bitmap bmap = bitmap; + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return 0; + + return bmap->cluster_bits; +} + +errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap, + ext2_ino_t end, ext2_ino_t *oend) +{ + __u64 tmp_oend; + int retval; + + retval = ext2fs_fudge_generic_bmap_end((ext2fs_generic_bitmap) bitmap, + EXT2_ET_FUDGE_INODE_BITMAP_END, + end, &tmp_oend); + if (oend) + *oend = tmp_oend; + return retval; +} + +errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap, + blk_t end, blk_t *oend) +{ + return (ext2fs_fudge_generic_bitmap_end(bitmap, + EXT2_ET_MAGIC_BLOCK_BITMAP, + EXT2_ET_FUDGE_BLOCK_BITMAP_END, + end, oend)); +} + +errcode_t ext2fs_fudge_block_bitmap_end2(ext2fs_block_bitmap bitmap, + blk64_t end, blk64_t *oend) +{ + return (ext2fs_fudge_generic_bmap_end(bitmap, + EXT2_ET_FUDGE_BLOCK_BITMAP_END, + end, oend)); +} + +void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap) +{ + ext2fs_clear_generic_bmap(bitmap); +} + +void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap) +{ + ext2fs_clear_generic_bmap(bitmap); +} + +errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end, + ext2fs_inode_bitmap bmap) +{ + return (ext2fs_resize_generic_bitmap(EXT2_ET_MAGIC_INODE_BITMAP, + new_end, new_real_end, bmap)); +} + +errcode_t ext2fs_resize_inode_bitmap2(__u64 new_end, __u64 new_real_end, + ext2fs_inode_bitmap bmap) +{ + return (ext2fs_resize_generic_bmap(bmap, new_end, new_real_end)); +} + +errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end, + ext2fs_block_bitmap bmap) +{ + return (ext2fs_resize_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, + new_end, new_real_end, bmap)); +} + +errcode_t ext2fs_resize_block_bitmap2(__u64 new_end, __u64 new_real_end, + ext2fs_block_bitmap bmap) +{ + return (ext2fs_resize_generic_bmap(bmap, new_end, new_real_end)); +} + +errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1, + ext2fs_block_bitmap bm2) +{ + return (ext2fs_compare_generic_bmap(EXT2_ET_NEQ_BLOCK_BITMAP, + bm1, bm2)); +} + +errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1, + ext2fs_inode_bitmap bm2) +{ + return (ext2fs_compare_generic_bmap(EXT2_ET_NEQ_INODE_BITMAP, + bm1, bm2)); +} + +errcode_t ext2fs_set_inode_bitmap_range(ext2fs_inode_bitmap bmap, + ext2_ino_t start, unsigned int num, + void *in) +{ + return (ext2fs_set_generic_bitmap_range(bmap, + EXT2_ET_MAGIC_INODE_BITMAP, + start, num, in)); +} + +errcode_t ext2fs_set_inode_bitmap_range2(ext2fs_inode_bitmap bmap, + __u64 start, size_t num, + void *in) +{ + return (ext2fs_set_generic_bmap_range(bmap, start, num, in)); +} + +errcode_t ext2fs_get_inode_bitmap_range(ext2fs_inode_bitmap bmap, + ext2_ino_t start, unsigned int num, + void *out) +{ + return (ext2fs_get_generic_bitmap_range(bmap, + EXT2_ET_MAGIC_INODE_BITMAP, + start, num, out)); +} + +errcode_t ext2fs_get_inode_bitmap_range2(ext2fs_inode_bitmap bmap, + __u64 start, size_t num, + void *out) +{ + return (ext2fs_get_generic_bmap_range(bmap, start, num, out)); +} + +errcode_t ext2fs_set_block_bitmap_range(ext2fs_block_bitmap bmap, + blk_t start, unsigned int num, + void *in) +{ + return (ext2fs_set_generic_bitmap_range(bmap, + EXT2_ET_MAGIC_BLOCK_BITMAP, + start, num, in)); +} + +errcode_t ext2fs_set_block_bitmap_range2(ext2fs_block_bitmap bmap, + blk64_t start, size_t num, + void *in) +{ + return (ext2fs_set_generic_bmap_range(bmap, start, num, in)); +} + +errcode_t ext2fs_get_block_bitmap_range(ext2fs_block_bitmap bmap, + blk_t start, unsigned int num, + void *out) +{ + return (ext2fs_get_generic_bitmap_range(bmap, + EXT2_ET_MAGIC_BLOCK_BITMAP, + start, num, out)); +} + +errcode_t ext2fs_get_block_bitmap_range2(ext2fs_block_bitmap bmap, + blk64_t start, size_t num, + void *out) +{ + return (ext2fs_get_generic_bmap_range(bmap, start, num, out)); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/bitops.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/bitops.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,158 @@ +/* + * bitops.c --- Bitmap frobbing code. See bitops.h for the inlined + * routines. + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +#ifndef _EXT2_HAVE_ASM_BITOPS_ + +/* + * For the benefit of those who are trying to port Linux to another + * architecture, here are some C-language equivalents. You should + * recode these in the native assembly language, if at all possible. + * + * C language equivalents written by Theodore Ts'o, 9/26/92. + * Modified by Pete A. Zaitcev 7/14/95 to be portable to big endian + * systems, as well as non-32 bit systems. + */ + +int ext2fs_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 ext2fs_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 ext2fs_test_bit(unsigned int nr, const void * addr) +{ + int mask; + const unsigned char *ADDR = (const unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + return (mask & *ADDR); +} + +#endif /* !_EXT2_HAVE_ASM_BITOPS_ */ + +void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg, + const char *description) +{ +#ifndef OMIT_COM_ERR + if (description) + com_err(0, errcode, "#%lu for %s", arg, description); + else + com_err(0, errcode, "#%lu", arg); +#endif +} + +/* + * C-only 64 bit ops. + */ + +int ext2fs_set_bit64(__u64 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 ext2fs_clear_bit64(__u64 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 ext2fs_test_bit64(__u64 nr, const void * addr) +{ + int mask; + const unsigned char *ADDR = (const unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + return (mask & *ADDR); +} + +static unsigned int popcount8(unsigned int w) +{ + unsigned int res = w - ((w >> 1) & 0x55); + res = (res & 0x33) + ((res >> 2) & 0x33); + return (res + (res >> 4)) & 0x0F; +} + +static unsigned int popcount32(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; +} + +unsigned int ext2fs_bitcount(const void *addr, unsigned int nbytes) +{ + const unsigned char *cp = addr; + const __u32 *p; + unsigned int res = 0; + + while (((((uintptr_t) cp) & 3) != 0) && (nbytes > 0)) { + res += popcount8(*cp++); + nbytes--; + } + p = (const __u32 *) cp; + + while (nbytes > 4) { + res += popcount32(*p++); + nbytes -= 4; + } + cp = (const unsigned char *) p; + + while (nbytes > 0) { + res += popcount8(*cp++); + nbytes--; + } + return res; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/blkmap64_ba.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/blkmap64_ba.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,492 @@ +/* + * blkmap64_ba.c --- Simple bitarray implementation for bitmaps + * + * Copyright (C) 2008 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" +#include "bmap64.h" + +/* + * Private data for bit array implementation of bitmap ops. + * Currently, this is just a pointer to our big flat hunk of memory, + * exactly equivalent to the old-skool char * bitmap member. + */ + +struct ext2fs_ba_private_struct { + char *bitarray; +}; + +typedef struct ext2fs_ba_private_struct *ext2fs_ba_private; + +static errcode_t ba_alloc_private_data (ext2fs_generic_bitmap bitmap) +{ + ext2fs_ba_private bp; + errcode_t retval; + size_t size; + + /* + * Since we only have the one pointer, we could just shove our + * private data in the void *private field itself, but then + * we'd have to do a fair bit of rewriting if we ever added a + * field. I'm agnostic. + */ + retval = ext2fs_get_mem(sizeof (ext2fs_ba_private), &bp); + if (retval) + return retval; + + size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1); + + retval = ext2fs_get_mem(size, &bp->bitarray); + if (retval) { + ext2fs_free_mem(&bp); + bp = 0; + return retval; + } + bitmap->private = (void *) bp; + return 0; +} + +static errcode_t ba_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)), + ext2fs_generic_bitmap bitmap) +{ + ext2fs_ba_private bp; + errcode_t retval; + size_t size; + + retval = ba_alloc_private_data (bitmap); + if (retval) + return retval; + + bp = (ext2fs_ba_private) bitmap->private; + size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1); + memset(bp->bitarray, 0, size); + + return 0; +} + +static void ba_free_bmap(ext2fs_generic_bitmap bitmap) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + + if (!bp) + return; + + if (bp->bitarray) { + ext2fs_free_mem (&bp->bitarray); + bp->bitarray = 0; + } + ext2fs_free_mem (&bp); + bp = 0; +} + +static errcode_t ba_copy_bmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap dest) +{ + ext2fs_ba_private src_bp = (ext2fs_ba_private) src->private; + ext2fs_ba_private dest_bp; + errcode_t retval; + size_t size; + + retval = ba_alloc_private_data (dest); + if (retval) + return retval; + + dest_bp = (ext2fs_ba_private) dest->private; + + size = (size_t) (((src->real_end - src->start) / 8) + 1); + memcpy (dest_bp->bitarray, src_bp->bitarray, size); + + return 0; +} + +static errcode_t ba_resize_bmap(ext2fs_generic_bitmap bmap, + __u64 new_end, __u64 new_real_end) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bmap->private; + errcode_t retval; + size_t size, new_size; + __u64 bitno; + + /* + * If we're expanding the bitmap, make sure all of the new + * parts of the bitmap are zero. + */ + if (new_end > bmap->end) { + bitno = bmap->real_end; + if (bitno > new_end) + bitno = new_end; + for (; bitno > bmap->end; bitno--) + ext2fs_clear_bit64(bitno - bmap->start, bp->bitarray); + } + if (new_real_end == bmap->real_end) { + bmap->end = new_end; + return 0; + } + + size = ((bmap->real_end - bmap->start) / 8) + 1; + new_size = ((new_real_end - bmap->start) / 8) + 1; + + if (size != new_size) { + retval = ext2fs_resize_mem(size, new_size, &bp->bitarray); + if (retval) + return retval; + } + if (new_size > size) + memset(bp->bitarray + size, 0, new_size - size); + + bmap->end = new_end; + bmap->real_end = new_real_end; + return 0; + +} + +static int ba_mark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + blk64_t bitno = (blk64_t) arg; + + return ext2fs_set_bit64(bitno - bitmap->start, bp->bitarray); +} + +static int ba_unmark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + blk64_t bitno = (blk64_t) arg; + + return ext2fs_clear_bit64(bitno - bitmap->start, bp->bitarray); +} + +static int ba_test_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + blk64_t bitno = (blk64_t) arg; + + return ext2fs_test_bit64(bitno - bitmap->start, bp->bitarray); +} + +static void ba_mark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg, + unsigned int num) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + blk64_t bitno = (blk64_t) arg; + unsigned int i; + + for (i = 0; i < num; i++) + ext2fs_fast_set_bit64(bitno + i - bitmap->start, bp->bitarray); +} + +static void ba_unmark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg, + unsigned int num) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + blk64_t bitno = (blk64_t) arg; + unsigned int i; + + for (i = 0; i < num; i++) + ext2fs_fast_clear_bit64(bitno + i - bitmap->start, bp->bitarray); +} + +static int ba_test_clear_bmap_extent(ext2fs_generic_bitmap bitmap, + __u64 start, unsigned int len) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + __u64 start_byte, len_byte = len >> 3; + unsigned int start_bit, len_bit = len % 8; + unsigned int first_bit = 0; + unsigned int last_bit = 0; + int mark_count = 0; + int mark_bit = 0; + int i; + const char *ADDR; + + ADDR = bp->bitarray; + start -= bitmap->start; + start_byte = start >> 3; + start_bit = start % 8; + + if (start_bit != 0) { + /* + * The compared start block number or start inode number + * is not the first bit in a byte. + */ + mark_count = 8 - start_bit; + if (len < 8 - start_bit) { + mark_count = (int)len; + mark_bit = len + start_bit - 1; + } else + mark_bit = 7; + + for (i = mark_count; i > 0; i--, mark_bit--) + first_bit |= 1 << mark_bit; + + /* + * Compare blocks or inodes in the first byte. + * If there is any marked bit, this function returns 0. + */ + if (first_bit & ADDR[start_byte]) + return 0; + else if (len <= 8 - start_bit) + return 1; + + start_byte++; + len_bit = (len - mark_count) % 8; + len_byte = (len - mark_count) >> 3; + } + + /* + * The compared start block number or start inode number is + * the first bit in a byte. + */ + if (len_bit != 0) { + /* + * The compared end block number or end inode number is + * not the last bit in a byte. + */ + for (mark_bit = len_bit - 1; mark_bit >= 0; mark_bit--) + last_bit |= 1 << mark_bit; + + /* + * Compare blocks or inodes in the last byte. + * If there is any marked bit, this function returns 0. + */ + if (last_bit & ADDR[start_byte + len_byte]) + return 0; + else if (len_byte == 0) + return 1; + } + + /* Check whether all bytes are 0 */ + return ext2fs_mem_is_zero(ADDR + start_byte, len_byte); +} + + +static errcode_t ba_set_bmap_range(ext2fs_generic_bitmap bitmap, + __u64 start, size_t num, void *in) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + + memcpy (bp->bitarray + (start >> 3), in, (num + 7) >> 3); + + return 0; +} + +static errcode_t ba_get_bmap_range(ext2fs_generic_bitmap bitmap, + __u64 start, size_t num, void *out) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + + memcpy (out, bp->bitarray + (start >> 3), (num + 7) >> 3); + + return 0; +} + +static void ba_clear_bmap(ext2fs_generic_bitmap bitmap) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + + memset(bp->bitarray, 0, + (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1)); +} + +#ifdef ENABLE_BMAP_STATS +static void ba_print_stats(ext2fs_generic_bitmap bitmap) +{ + fprintf(stderr, "%16llu Bytes used by bitarray\n", + ((bitmap->real_end - bitmap->start) >> 3) + 1 + + sizeof(struct ext2fs_ba_private_struct)); +} +#else +static void ba_print_stats(ext2fs_generic_bitmap bitmap EXT2FS_ATTR((unused))) +{ +} +#endif + +/* Find the first zero bit between start and end, inclusive. */ +static errcode_t ba_find_first_zero(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out) +{ + ext2fs_ba_private bp = (ext2fs_ba_private)bitmap->private; + unsigned long bitpos = start - bitmap->start; + unsigned long count = end - start + 1; + int byte_found = 0; /* whether a != 0xff byte has been found */ + const unsigned char *pos; + unsigned long max_loop_count, i; + + /* scan bits until we hit a byte boundary */ + while ((bitpos & 0x7) != 0 && count > 0) { + if (!ext2fs_test_bit64(bitpos, bp->bitarray)) { + *out = bitpos + bitmap->start; + return 0; + } + bitpos++; + count--; + } + + if (!count) + return ENOENT; + + pos = ((unsigned char *)bp->bitarray) + (bitpos >> 3); + /* scan bytes until 8-byte (64-bit) aligned */ + while (count >= 8 && (((uintptr_t)pos) & 0x07)) { + if (*pos != 0xff) { + byte_found = 1; + break; + } + pos++; + count -= 8; + bitpos += 8; + } + + if (!byte_found) { + max_loop_count = count >> 6; /* 8-byte blocks */ + i = max_loop_count; + while (i) { + if (*((const __u64 *)pos) != ((__u64)-1)) + break; + pos += 8; + i--; + } + count -= 64 * (max_loop_count - i); + bitpos += 64 * (max_loop_count - i); + + max_loop_count = count >> 3; + i = max_loop_count; + while (i) { + if (*pos != 0xff) { + byte_found = 1; + break; + } + pos++; + i--; + } + count -= 8 * (max_loop_count - i); + bitpos += 8 * (max_loop_count - i); + } + + /* Here either count < 8 or byte_found == 1. */ + while (count-- > 0) { + if (!ext2fs_test_bit64(bitpos, bp->bitarray)) { + *out = bitpos + bitmap->start; + return 0; + } + bitpos++; + } + + return ENOENT; +} + +/* Find the first one bit between start and end, inclusive. */ +static errcode_t ba_find_first_set(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out) +{ + ext2fs_ba_private bp = (ext2fs_ba_private)bitmap->private; + unsigned long bitpos = start - bitmap->start; + unsigned long count = end - start + 1; + int byte_found = 0; /* whether a != 0xff byte has been found */ + const unsigned char *pos; + unsigned long max_loop_count, i; + + /* scan bits until we hit a byte boundary */ + while ((bitpos & 0x7) != 0 && count > 0) { + if (ext2fs_test_bit64(bitpos, bp->bitarray)) { + *out = bitpos + bitmap->start; + return 0; + } + bitpos++; + count--; + } + + if (!count) + return ENOENT; + + pos = ((unsigned char *)bp->bitarray) + (bitpos >> 3); + /* scan bytes until 8-byte (64-bit) aligned */ + while (count >= 8 && (((uintptr_t)pos) & 0x07)) { + if (*pos != 0) { + byte_found = 1; + break; + } + pos++; + count -= 8; + bitpos += 8; + } + + if (!byte_found) { + max_loop_count = count >> 6; /* 8-byte blocks */ + i = max_loop_count; + while (i) { + if (*((const __u64 *)pos) != 0) + break; + pos += 8; + i--; + } + count -= 64 * (max_loop_count - i); + bitpos += 64 * (max_loop_count - i); + + max_loop_count = count >> 3; + i = max_loop_count; + while (i) { + if (*pos != 0) { + byte_found = 1; + break; + } + pos++; + i--; + } + count -= 8 * (max_loop_count - i); + bitpos += 8 * (max_loop_count - i); + } + + /* Here either count < 8 or byte_found == 1. */ + while (count-- > 0) { + if (ext2fs_test_bit64(bitpos, bp->bitarray)) { + *out = bitpos + bitmap->start; + return 0; + } + bitpos++; + } + + return ENOENT; +} + +struct ext2_bitmap_ops ext2fs_blkmap64_bitarray = { + .type = EXT2FS_BMAP64_BITARRAY, + .new_bmap = ba_new_bmap, + .free_bmap = ba_free_bmap, + .copy_bmap = ba_copy_bmap, + .resize_bmap = ba_resize_bmap, + .mark_bmap = ba_mark_bmap, + .unmark_bmap = ba_unmark_bmap, + .test_bmap = ba_test_bmap, + .test_clear_bmap_extent = ba_test_clear_bmap_extent, + .mark_bmap_extent = ba_mark_bmap_extent, + .unmark_bmap_extent = ba_unmark_bmap_extent, + .set_bmap_range = ba_set_bmap_range, + .get_bmap_range = ba_get_bmap_range, + .clear_bmap = ba_clear_bmap, + .print_stats = ba_print_stats, + .find_first_zero = ba_find_first_zero, + .find_first_set = ba_find_first_set +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/blkmap64_rb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/blkmap64_rb.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,989 @@ +/* + * blkmap64_rb.c --- Simple rb-tree implementation for bitmaps + * + * (C)2010 Red Hat, Inc., Lukas Czerner + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_LINUX_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" +#include "bmap64.h" +#include "rbtree.h" + +#include + +struct bmap_rb_extent { + struct rb_node node; + __u64 start; + __u64 count; +}; + +struct ext2fs_rb_private { + struct rb_root root; + struct bmap_rb_extent *wcursor; + struct bmap_rb_extent *rcursor; + struct bmap_rb_extent *rcursor_next; +#ifdef ENABLE_BMAP_STATS_OPS + __u64 mark_hit; + __u64 test_hit; +#endif +}; + +inline static struct bmap_rb_extent *node_to_extent(struct rb_node *node) +{ + /* + * This depends on the fact the struct rb_node is at the + * beginning of the bmap_rb_extent structure. We use this + * instead of the ext2fs_rb_entry macro because it causes gcc + * -Wall to generate a huge amount of noise. + */ + return (struct bmap_rb_extent *) node; +} + +static int rb_insert_extent(__u64 start, __u64 count, + struct ext2fs_rb_private *); +static void rb_get_new_extent(struct bmap_rb_extent **, __u64, __u64); + +/* #define DEBUG_RB */ + +#ifdef DEBUG_RB +static void print_tree(struct rb_root *root) +{ + struct rb_node *node = NULL; + struct bmap_rb_extent *ext; + + fprintf(stderr, "\t\t\t=================================\n"); + node = ext2fs_rb_first(root); + for (node = ext2fs_rb_first(root); node != NULL; + node = ext2fs_rb_next(node)) { + ext = node_to_extent(node); + fprintf(stderr, "\t\t\t--> (%llu -> %llu)\n", + ext->start, ext->start + ext->count); + } + fprintf(stderr, "\t\t\t=================================\n"); +} + +static void check_tree(struct rb_root *root, const char *msg) +{ + struct rb_node *node; + struct bmap_rb_extent *ext, *old = NULL; + + for (node = ext2fs_rb_first(root); node; + node = ext2fs_rb_next(node)) { + ext = node_to_extent(node); + if (ext->count == 0) { + fprintf(stderr, "Tree Error: count is zero\n"); + fprintf(stderr, "extent: %llu -> %llu (%llu)\n", + ext->start, ext->start + ext->count, + ext->count); + goto err_out; + } + if (ext->start + ext->count < ext->start) { + fprintf(stderr, + "Tree Error: start or count is crazy\n"); + fprintf(stderr, "extent: %llu -> %llu (%llu)\n", + ext->start, ext->start + ext->count, + ext->count); + goto err_out; + } + + if (old) { + if (old->start > ext->start) { + fprintf(stderr, "Tree Error: start is crazy\n"); + fprintf(stderr, "extent: %llu -> %llu (%llu)\n", + old->start, old->start + old->count, + old->count); + fprintf(stderr, + "extent next: %llu -> %llu (%llu)\n", + ext->start, ext->start + ext->count, + ext->count); + goto err_out; + } + if ((old->start + old->count) >= ext->start) { + fprintf(stderr, + "Tree Error: extent is crazy\n"); + fprintf(stderr, "extent: %llu -> %llu (%llu)\n", + old->start, old->start + old->count, + old->count); + fprintf(stderr, + "extent next: %llu -> %llu (%llu)\n", + ext->start, ext->start + ext->count, + ext->count); + goto err_out; + } + } + old = ext; + } + return; + +err_out: + fprintf(stderr, "%s\n", msg); + print_tree(root); + exit(1); +} +#else +#define check_tree(root, msg) do {} while (0) +#define print_tree(root) do {} while (0) +#endif + +static void rb_get_new_extent(struct bmap_rb_extent **ext, __u64 start, + __u64 count) +{ + struct bmap_rb_extent *new_ext; + int retval; + + retval = ext2fs_get_mem(sizeof (struct bmap_rb_extent), + &new_ext); + if (retval) + abort(); + + new_ext->start = start; + new_ext->count = count; + *ext = new_ext; +} + +inline +static void rb_free_extent(struct ext2fs_rb_private *bp, + struct bmap_rb_extent *ext) +{ + if (bp->wcursor == ext) + bp->wcursor = NULL; + if (bp->rcursor == ext) + bp->rcursor = NULL; + if (bp->rcursor_next == ext) + bp->rcursor_next = NULL; + ext2fs_free_mem(&ext); +} + +static errcode_t rb_alloc_private_data (ext2fs_generic_bitmap bitmap) +{ + struct ext2fs_rb_private *bp; + errcode_t retval; + + retval = ext2fs_get_mem(sizeof (struct ext2fs_rb_private), &bp); + if (retval) + return retval; + + bp->root = RB_ROOT; + bp->rcursor = NULL; + bp->rcursor_next = NULL; + bp->wcursor = NULL; + +#ifdef ENABLE_BMAP_STATS_OPS + bp->test_hit = 0; + bp->mark_hit = 0; +#endif + + bitmap->private = (void *) bp; + return 0; +} + +static errcode_t rb_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)), + ext2fs_generic_bitmap bitmap) +{ + errcode_t retval; + + retval = rb_alloc_private_data (bitmap); + if (retval) + return retval; + + return 0; +} + +static void rb_free_tree(struct rb_root *root) +{ + struct bmap_rb_extent *ext; + struct rb_node *node, *next; + + for (node = ext2fs_rb_first(root); node; node = next) { + next = ext2fs_rb_next(node); + ext = node_to_extent(node); + ext2fs_rb_erase(node, root); + ext2fs_free_mem(&ext); + } +} + +static void rb_free_bmap(ext2fs_generic_bitmap bitmap) +{ + struct ext2fs_rb_private *bp; + + bp = (struct ext2fs_rb_private *) bitmap->private; + + rb_free_tree(&bp->root); + ext2fs_free_mem(&bp); + bp = 0; +} + +static errcode_t rb_copy_bmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap dest) +{ + struct ext2fs_rb_private *src_bp, *dest_bp; + struct bmap_rb_extent *src_ext, *dest_ext; + struct rb_node *dest_node, *src_node, *dest_last, **n; + errcode_t retval = 0; + + retval = rb_alloc_private_data (dest); + if (retval) + return retval; + + src_bp = (struct ext2fs_rb_private *) src->private; + dest_bp = (struct ext2fs_rb_private *) dest->private; + src_bp->rcursor = NULL; + dest_bp->rcursor = NULL; + + src_node = ext2fs_rb_first(&src_bp->root); + while (src_node) { + src_ext = node_to_extent(src_node); + retval = ext2fs_get_mem(sizeof (struct bmap_rb_extent), + &dest_ext); + if (retval) + break; + + memcpy(dest_ext, src_ext, sizeof(struct bmap_rb_extent)); + + dest_node = &dest_ext->node; + n = &dest_bp->root.rb_node; + + dest_last = NULL; + if (*n) { + dest_last = ext2fs_rb_last(&dest_bp->root); + n = &(dest_last)->rb_right; + } + + ext2fs_rb_link_node(dest_node, dest_last, n); + ext2fs_rb_insert_color(dest_node, &dest_bp->root); + + src_node = ext2fs_rb_next(src_node); + } + + return retval; +} + +static void rb_truncate(__u64 new_max, struct rb_root *root) +{ + struct bmap_rb_extent *ext; + struct rb_node *node; + + node = ext2fs_rb_last(root); + while (node) { + ext = node_to_extent(node); + + if ((ext->start + ext->count - 1) <= new_max) + break; + else if (ext->start > new_max) { + ext2fs_rb_erase(node, root); + ext2fs_free_mem(&ext); + node = ext2fs_rb_last(root); + continue; + } else + ext->count = new_max - ext->start + 1; + } +} + +static errcode_t rb_resize_bmap(ext2fs_generic_bitmap bmap, + __u64 new_end, __u64 new_real_end) +{ + struct ext2fs_rb_private *bp; + + bp = (struct ext2fs_rb_private *) bmap->private; + bp->rcursor = NULL; + bp->wcursor = NULL; + + rb_truncate(((new_end < bmap->end) ? new_end : bmap->end) - bmap->start, + &bp->root); + + bmap->end = new_end; + bmap->real_end = new_real_end; + + if (bmap->end < bmap->real_end) + rb_insert_extent(bmap->end + 1 - bmap->start, + bmap->real_end - bmap->end, bp); + return 0; + +} + +inline static int +rb_test_bit(struct ext2fs_rb_private *bp, __u64 bit) +{ + struct bmap_rb_extent *rcursor, *next_ext = NULL; + struct rb_node *parent = NULL, *next; + struct rb_node **n = &bp->root.rb_node; + struct bmap_rb_extent *ext; + + rcursor = bp->rcursor; + if (!rcursor) + goto search_tree; + + if (bit >= rcursor->start && bit < rcursor->start + rcursor->count) { +#ifdef ENABLE_BMAP_STATS_OPS + bp->test_hit++; +#endif + return 1; + } + + next_ext = bp->rcursor_next; + if (!next_ext) { + next = ext2fs_rb_next(&rcursor->node); + if (next) + next_ext = node_to_extent(next); + bp->rcursor_next = next_ext; + } + if (next_ext) { + if ((bit >= rcursor->start + rcursor->count) && + (bit < next_ext->start)) { +#ifdef BMAP_STATS_OPS + bp->test_hit++; +#endif + return 0; + } + } + bp->rcursor = NULL; + bp->rcursor_next = NULL; + + rcursor = bp->wcursor; + if (!rcursor) + goto search_tree; + + if (bit >= rcursor->start && bit < rcursor->start + rcursor->count) + return 1; + +search_tree: + + while (*n) { + parent = *n; + ext = node_to_extent(parent); + if (bit < ext->start) + n = &(*n)->rb_left; + else if (bit >= (ext->start + ext->count)) + n = &(*n)->rb_right; + else { + bp->rcursor = ext; + bp->rcursor_next = NULL; + return 1; + } + } + return 0; +} + +static int rb_insert_extent(__u64 start, __u64 count, + struct ext2fs_rb_private *bp) +{ + struct rb_root *root = &bp->root; + struct rb_node *parent = NULL, **n = &root->rb_node; + struct rb_node *new_node, *node, *next; + struct bmap_rb_extent *new_ext; + struct bmap_rb_extent *ext; + int retval = 0; + + if (count == 0) + return 0; + + bp->rcursor_next = NULL; + ext = bp->wcursor; + if (ext) { + if (start >= ext->start && + start <= (ext->start + ext->count)) { +#ifdef ENABLE_BMAP_STATS_OPS + bp->mark_hit++; +#endif + goto got_extent; + } + } + + while (*n) { + parent = *n; + ext = node_to_extent(parent); + + if (start < ext->start) { + n = &(*n)->rb_left; + } else if (start > (ext->start + ext->count)) { + n = &(*n)->rb_right; + } else { +got_extent: + if ((start + count) <= (ext->start + ext->count)) + return 1; + + if ((ext->start + ext->count) == start) + retval = 0; + else + retval = 1; + + count += (start - ext->start); + start = ext->start; + new_ext = ext; + new_node = &ext->node; + + goto skip_insert; + } + } + + rb_get_new_extent(&new_ext, start, count); + + new_node = &new_ext->node; + ext2fs_rb_link_node(new_node, parent, n); + ext2fs_rb_insert_color(new_node, root); + bp->wcursor = new_ext; + + node = ext2fs_rb_prev(new_node); + if (node) { + ext = node_to_extent(node); + if ((ext->start + ext->count) == start) { + start = ext->start; + count += ext->count; + ext2fs_rb_erase(node, root); + rb_free_extent(bp, ext); + } + } + +skip_insert: + /* See if we can merge extent to the right */ + for (node = ext2fs_rb_next(new_node); node != NULL; node = next) { + next = ext2fs_rb_next(node); + ext = node_to_extent(node); + + if ((ext->start + ext->count) <= start) + continue; + + /* No more merging */ + if ((start + count) < ext->start) + break; + + /* ext is embedded in new_ext interval */ + if ((start + count) >= (ext->start + ext->count)) { + ext2fs_rb_erase(node, root); + rb_free_extent(bp, ext); + continue; + } else { + /* merge ext with new_ext */ + count += ((ext->start + ext->count) - + (start + count)); + ext2fs_rb_erase(node, root); + rb_free_extent(bp, ext); + break; + } + } + + new_ext->start = start; + new_ext->count = count; + + return retval; +} + +static int rb_remove_extent(__u64 start, __u64 count, + struct ext2fs_rb_private *bp) +{ + struct rb_root *root = &bp->root; + struct rb_node *parent = NULL, **n = &root->rb_node; + struct rb_node *node; + struct bmap_rb_extent *ext; + __u64 new_start, new_count; + int retval = 0; + + if (ext2fs_rb_empty_root(root)) + return 0; + + while (*n) { + parent = *n; + ext = node_to_extent(parent); + if (start < ext->start) { + n = &(*n)->rb_left; + continue; + } else if (start >= (ext->start + ext->count)) { + n = &(*n)->rb_right; + continue; + } + + if ((start > ext->start) && + (start + count) < (ext->start + ext->count)) { + /* We have to split extent into two */ + new_start = start + count; + new_count = (ext->start + ext->count) - new_start; + + ext->count = start - ext->start; + + rb_insert_extent(new_start, new_count, bp); + return 1; + } + + if ((start + count) >= (ext->start + ext->count)) { + ext->count = start - ext->start; + retval = 1; + } + + if (0 == ext->count) { + parent = ext2fs_rb_next(&ext->node); + ext2fs_rb_erase(&ext->node, root); + rb_free_extent(bp, ext); + break; + } + + if (start == ext->start) { + ext->start += count; + ext->count -= count; + return 1; + } + } + + /* See if we should delete or truncate extent on the right */ + for (; parent != NULL; parent = node) { + node = ext2fs_rb_next(parent); + ext = node_to_extent(parent); + if ((ext->start + ext->count) <= start) + continue; + + /* No more extents to be removed/truncated */ + if ((start + count) < ext->start) + break; + + /* The entire extent is within the region to be removed */ + if ((start + count) >= (ext->start + ext->count)) { + ext2fs_rb_erase(parent, root); + rb_free_extent(bp, ext); + retval = 1; + continue; + } else { + /* modify the last extent in region to be removed */ + ext->count -= ((start + count) - ext->start); + ext->start = start + count; + retval = 1; + break; + } + } + + return retval; +} + +static int rb_mark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) +{ + struct ext2fs_rb_private *bp; + int retval; + + bp = (struct ext2fs_rb_private *) bitmap->private; + arg -= bitmap->start; + + retval = rb_insert_extent(arg, 1, bp); + check_tree(&bp->root, __func__); + return retval; +} + +static int rb_unmark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) +{ + struct ext2fs_rb_private *bp; + int retval; + + bp = (struct ext2fs_rb_private *) bitmap->private; + arg -= bitmap->start; + + retval = rb_remove_extent(arg, 1, bp); + check_tree(&bp->root, __func__); + + return retval; +} + +inline +static int rb_test_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) +{ + struct ext2fs_rb_private *bp; + + bp = (struct ext2fs_rb_private *) bitmap->private; + arg -= bitmap->start; + + return rb_test_bit(bp, arg); +} + +static void rb_mark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg, + unsigned int num) +{ + struct ext2fs_rb_private *bp; + + bp = (struct ext2fs_rb_private *) bitmap->private; + arg -= bitmap->start; + + rb_insert_extent(arg, num, bp); + check_tree(&bp->root, __func__); +} + +static void rb_unmark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg, + unsigned int num) +{ + struct ext2fs_rb_private *bp; + + bp = (struct ext2fs_rb_private *) bitmap->private; + arg -= bitmap->start; + + rb_remove_extent(arg, num, bp); + check_tree(&bp->root, __func__); +} + +static int rb_test_clear_bmap_extent(ext2fs_generic_bitmap bitmap, + __u64 start, unsigned int len) +{ + struct rb_node *parent = NULL, **n; + struct rb_node *node, *next; + struct ext2fs_rb_private *bp; + struct bmap_rb_extent *ext; + int retval = 1; + + bp = (struct ext2fs_rb_private *) bitmap->private; + n = &bp->root.rb_node; + start -= bitmap->start; + + if (len == 0 || ext2fs_rb_empty_root(&bp->root)) + return 1; + + /* + * If we find nothing, we should examine whole extent, but + * when we find match, the extent is not clean, thus be return + * false. + */ + while (*n) { + parent = *n; + ext = node_to_extent(parent); + if (start < ext->start) { + n = &(*n)->rb_left; + } else if (start >= (ext->start + ext->count)) { + n = &(*n)->rb_right; + } else { + /* + * We found extent int the tree -> extent is not + * clean + */ + return 0; + } + } + + node = parent; + while (node) { + next = ext2fs_rb_next(node); + ext = node_to_extent(node); + node = next; + + if ((ext->start + ext->count) <= start) + continue; + + /* No more merging */ + if ((start + len) <= ext->start) + break; + + retval = 0; + break; + } + return retval; +} + +static errcode_t rb_set_bmap_range(ext2fs_generic_bitmap bitmap, + __u64 start, size_t num, void *in) +{ + struct ext2fs_rb_private *bp; + unsigned char *cp = in; + size_t i; + int first_set = -1; + + bp = (struct ext2fs_rb_private *) bitmap->private; + + for (i = 0; i < num; i++) { + if ((i & 7) == 0) { + unsigned char c = cp[i/8]; + if (c == 0xFF) { + if (first_set == -1) + first_set = i; + i += 7; + continue; + } + if ((c == 0x00) && (first_set == -1)) { + i += 7; + continue; + } + } + if (ext2fs_test_bit(i, in)) { + if (first_set == -1) + first_set = i; + continue; + } + if (first_set == -1) + continue; + + rb_insert_extent(start + first_set - bitmap->start, + i - first_set, bp); + check_tree(&bp->root, __func__); + first_set = -1; + } + if (first_set != -1) { + rb_insert_extent(start + first_set - bitmap->start, + num - first_set, bp); + check_tree(&bp->root, __func__); + } + + return 0; +} + +static errcode_t rb_get_bmap_range(ext2fs_generic_bitmap bitmap, + __u64 start, size_t num, void *out) +{ + + struct rb_node *parent = NULL, *next, **n; + struct ext2fs_rb_private *bp; + struct bmap_rb_extent *ext; + __u64 count, pos; + + bp = (struct ext2fs_rb_private *) bitmap->private; + n = &bp->root.rb_node; + start -= bitmap->start; + + if (ext2fs_rb_empty_root(&bp->root)) + return 0; + + while (*n) { + parent = *n; + ext = node_to_extent(parent); + if (start < ext->start) { + n = &(*n)->rb_left; + } else if (start >= (ext->start + ext->count)) { + n = &(*n)->rb_right; + } else + break; + } + + memset(out, 0, (num + 7) >> 3); + + for (; parent != NULL; parent = next) { + next = ext2fs_rb_next(parent); + ext = node_to_extent(parent); + + pos = ext->start; + count = ext->count; + if (pos >= start + num) + break; + if (pos < start) { + if (pos + count < start) + continue; + count -= start - pos; + pos = start; + } + if (pos + count > start + num) + count = start + num - pos; + + while (count > 0) { + if ((count >= 8) && + ((pos - start) % 8) == 0) { + int nbytes = count >> 3; + int offset = (pos - start) >> 3; + + memset(((char *) out) + offset, 0xFF, nbytes); + pos += nbytes << 3; + count -= nbytes << 3; + continue; + } + ext2fs_fast_set_bit64((pos - start), out); + pos++; + count--; + } + } + return 0; +} + +static void rb_clear_bmap(ext2fs_generic_bitmap bitmap) +{ + struct ext2fs_rb_private *bp; + + bp = (struct ext2fs_rb_private *) bitmap->private; + + rb_free_tree(&bp->root); + bp->rcursor = NULL; + bp->rcursor_next = NULL; + bp->wcursor = NULL; + check_tree(&bp->root, __func__); +} + +static errcode_t rb_find_first_zero(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out) +{ + struct rb_node *parent = NULL, **n; + struct ext2fs_rb_private *bp; + struct bmap_rb_extent *ext; + + bp = (struct ext2fs_rb_private *) bitmap->private; + n = &bp->root.rb_node; + start -= bitmap->start; + end -= bitmap->start; + + if (start > end) + return EINVAL; + + if (ext2fs_rb_empty_root(&bp->root)) + return ENOENT; + + while (*n) { + parent = *n; + ext = node_to_extent(parent); + if (start < ext->start) { + n = &(*n)->rb_left; + } else if (start >= (ext->start + ext->count)) { + n = &(*n)->rb_right; + } else if (ext->start + ext->count <= end) { + *out = ext->start + ext->count + bitmap->start; + return 0; + } else + return ENOENT; + } + + *out = start + bitmap->start; + return 0; +} + +static errcode_t rb_find_first_set(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out) +{ + struct rb_node *parent = NULL, **n; + struct rb_node *node; + struct ext2fs_rb_private *bp; + struct bmap_rb_extent *ext; + + bp = (struct ext2fs_rb_private *) bitmap->private; + n = &bp->root.rb_node; + start -= bitmap->start; + end -= bitmap->start; + + if (start > end) + return EINVAL; + + if (ext2fs_rb_empty_root(&bp->root)) + return ENOENT; + + while (*n) { + parent = *n; + ext = node_to_extent(parent); + if (start < ext->start) { + n = &(*n)->rb_left; + } else if (start >= (ext->start + ext->count)) { + n = &(*n)->rb_right; + } else { + /* The start bit is set */ + *out = start + bitmap->start; + return 0; + } + } + + node = parent; + ext = node_to_extent(node); + if (ext->start < start) { + node = ext2fs_rb_next(node); + if (node == NULL) + return ENOENT; + ext = node_to_extent(node); + } + if (ext->start <= end) { + *out = ext->start + bitmap->start; + return 0; + } + return ENOENT; +} + +#ifdef ENABLE_BMAP_STATS +static void rb_print_stats(ext2fs_generic_bitmap bitmap) +{ + struct ext2fs_rb_private *bp; + struct rb_node *node = NULL; + struct bmap_rb_extent *ext; + __u64 count = 0; + __u64 max_size = 0; + __u64 min_size = ULONG_MAX; + __u64 size = 0, avg_size = 0; + double eff; +#ifdef ENABLE_BMAP_STATS_OPS + __u64 mark_all, test_all; + double m_hit = 0.0, t_hit = 0.0; +#endif + + bp = (struct ext2fs_rb_private *) bitmap->private; + + for (node = ext2fs_rb_first(&bp->root); node != NULL; + node = ext2fs_rb_next(node)) { + ext = node_to_extent(node); + count++; + if (ext->count > max_size) + max_size = ext->count; + if (ext->count < min_size) + min_size = ext->count; + size += ext->count; + } + + if (count) + avg_size = size / count; + if (min_size == ULONG_MAX) + min_size = 0; + eff = (double)((count * sizeof(struct bmap_rb_extent)) << 3) / + (bitmap->real_end - bitmap->start); +#ifdef ENABLE_BMAP_STATS_OPS + mark_all = bitmap->stats.mark_count + bitmap->stats.mark_ext_count; + test_all = bitmap->stats.test_count + bitmap->stats.test_ext_count; + if (mark_all) + m_hit = ((double)bp->mark_hit / mark_all) * 100; + if (test_all) + t_hit = ((double)bp->test_hit / test_all) * 100; + + fprintf(stderr, "%16llu cache hits on test (%.2f%%)\n" + "%16llu cache hits on mark (%.2f%%)\n", + bp->test_hit, t_hit, bp->mark_hit, m_hit); +#endif + fprintf(stderr, "%16llu extents (%llu bytes)\n", + count, ((count * sizeof(struct bmap_rb_extent)) + + sizeof(struct ext2fs_rb_private))); + fprintf(stderr, "%16llu bits minimum size\n", + min_size); + fprintf(stderr, "%16llu bits maximum size\n" + "%16llu bits average size\n", + max_size, avg_size); + fprintf(stderr, "%16llu bits set in bitmap (out of %llu)\n", size, + bitmap->real_end - bitmap->start); + fprintf(stderr, + "%16.4lf memory / bitmap bit memory ratio (bitarray = 1)\n", + eff); +} +#else +static void rb_print_stats(ext2fs_generic_bitmap bitmap EXT2FS_ATTR((unused))) +{ +} +#endif + +struct ext2_bitmap_ops ext2fs_blkmap64_rbtree = { + .type = EXT2FS_BMAP64_RBTREE, + .new_bmap = rb_new_bmap, + .free_bmap = rb_free_bmap, + .copy_bmap = rb_copy_bmap, + .resize_bmap = rb_resize_bmap, + .mark_bmap = rb_mark_bmap, + .unmark_bmap = rb_unmark_bmap, + .test_bmap = rb_test_bmap, + .test_clear_bmap_extent = rb_test_clear_bmap_extent, + .mark_bmap_extent = rb_mark_bmap_extent, + .unmark_bmap_extent = rb_unmark_bmap_extent, + .set_bmap_range = rb_set_bmap_range, + .get_bmap_range = rb_get_bmap_range, + .clear_bmap = rb_clear_bmap, + .print_stats = rb_print_stats, + .find_first_zero = rb_find_first_zero, + .find_first_set = rb_find_first_set, +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/blknum.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/blknum.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,543 @@ +/* + * blknum.c --- Functions to handle blk64_t and high/low 64-bit block + * number. + * + * Copyright IBM Corporation, 2007 + * Author Jose R. Santos + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "config.h" +#include "ext2fs.h" + +/* + * Return the group # of a block + */ +dgrp_t ext2fs_group_of_blk2(ext2_filsys fs, blk64_t blk) +{ + return (blk - fs->super->s_first_data_block) / + fs->super->s_blocks_per_group; +} + +/* + * Return the first block (inclusive) in a group + */ +blk64_t ext2fs_group_first_block2(ext2_filsys fs, dgrp_t group) +{ + return fs->super->s_first_data_block + + EXT2_GROUPS_TO_BLOCKS(fs->super, group); +} + +/* + * Return the last block (inclusive) in a group + */ +blk64_t ext2fs_group_last_block2(ext2_filsys fs, dgrp_t group) +{ + return (group == fs->group_desc_count - 1 ? + ext2fs_blocks_count(fs->super) - 1 : + ext2fs_group_first_block2(fs, group) + + (fs->super->s_blocks_per_group - 1)); +} + +/* + * Return the number of blocks in a group + */ +int ext2fs_group_blocks_count(ext2_filsys fs, dgrp_t group) +{ + int num_blocks; + + if (group == fs->group_desc_count - 1) { + num_blocks = (ext2fs_blocks_count(fs->super) - + fs->super->s_first_data_block) % + fs->super->s_blocks_per_group; + if (!num_blocks) + num_blocks = fs->super->s_blocks_per_group; + } else + num_blocks = fs->super->s_blocks_per_group; + + return num_blocks; +} + +/* + * Return the inode data block count + */ +blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs, + struct ext2_inode *inode) +{ + return (inode->i_blocks | + (ext2fs_has_feature_huge_file(fs->super) ? + (__u64) inode->osd2.linux2.l_i_blocks_hi << 32 : 0)) - + (inode->i_file_acl ? EXT2_CLUSTER_SIZE(fs->super) >> 9 : 0); +} + +/* + * Return the inode i_blocks count + */ +blk64_t ext2fs_inode_i_blocks(ext2_filsys fs, + struct ext2_inode *inode) +{ + return (inode->i_blocks | + (ext2fs_has_feature_huge_file(fs->super) ? + (__u64)inode->osd2.linux2.l_i_blocks_hi << 32 : 0)); +} + +/* + * Return the fs block count + */ +blk64_t ext2fs_blocks_count(struct ext2_super_block *super) +{ + return super->s_blocks_count | + (ext2fs_has_feature_64bit(super) ? + (__u64) super->s_blocks_count_hi << 32 : 0); +} + +/* + * Set the fs block count + */ +void ext2fs_blocks_count_set(struct ext2_super_block *super, blk64_t blk) +{ + super->s_blocks_count = blk; + if (ext2fs_has_feature_64bit(super)) + super->s_blocks_count_hi = (__u64) blk >> 32; +} + +/* + * Add to the current fs block count + */ +void ext2fs_blocks_count_add(struct ext2_super_block *super, blk64_t blk) +{ + blk64_t tmp; + tmp = ext2fs_blocks_count(super) + blk; + ext2fs_blocks_count_set(super, tmp); +} + +/* + * Return the fs reserved block count + */ +blk64_t ext2fs_r_blocks_count(struct ext2_super_block *super) +{ + return super->s_r_blocks_count | + (ext2fs_has_feature_64bit(super) ? + (__u64) super->s_r_blocks_count_hi << 32 : 0); +} + +/* + * Set the fs reserved block count + */ +void ext2fs_r_blocks_count_set(struct ext2_super_block *super, blk64_t blk) +{ + super->s_r_blocks_count = blk; + if (ext2fs_has_feature_64bit(super)) + super->s_r_blocks_count_hi = (__u64) blk >> 32; +} + +/* + * Add to the current reserved fs block count + */ +void ext2fs_r_blocks_count_add(struct ext2_super_block *super, blk64_t blk) +{ + blk64_t tmp; + tmp = ext2fs_r_blocks_count(super) + blk; + ext2fs_r_blocks_count_set(super, tmp); +} + +/* + * Return the fs free block count + */ +blk64_t ext2fs_free_blocks_count(struct ext2_super_block *super) +{ + return super->s_free_blocks_count | + (ext2fs_has_feature_64bit(super) ? + (__u64) super->s_free_blocks_hi << 32 : 0); +} + +/* + * Set the fs free block count + */ +void ext2fs_free_blocks_count_set(struct ext2_super_block *super, blk64_t blk) +{ + super->s_free_blocks_count = blk; + if (ext2fs_has_feature_64bit(super)) + super->s_free_blocks_hi = (__u64) blk >> 32; +} + +/* + * Add to the current free fs block count + */ +void ext2fs_free_blocks_count_add(struct ext2_super_block *super, blk64_t blk) +{ + blk64_t tmp; + tmp = ext2fs_free_blocks_count(super) + blk; + ext2fs_free_blocks_count_set(super, tmp); +} + +/* + * Get a pointer to a block group descriptor. We need the explicit + * pointer to the group desc for code that swaps block group + * descriptors before writing them out, as it wants to make a copy and + * do the swap there. + */ +struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs, + struct opaque_ext2_group_desc *gdp, + dgrp_t group) +{ + int desc_size = EXT2_DESC_SIZE(fs->super) & ~7; + + return (struct ext2_group_desc *)((char *)gdp + group * desc_size); +} + +/* Do the same but as an ext4 group desc for internal use here */ +static struct ext4_group_desc *ext4fs_group_desc(ext2_filsys fs, + struct opaque_ext2_group_desc *gdp, + dgrp_t group) +{ + return (struct ext4_group_desc *)ext2fs_group_desc(fs, gdp, group); +} + +/* + * Return the block bitmap checksum of a group + */ +__u32 ext2fs_block_bitmap_checksum(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + __u32 csum; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + csum = gdp->bg_block_bitmap_csum_lo; + if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) + csum |= ((__u32)gdp->bg_block_bitmap_csum_hi << 16); + return csum; +} + +/* + * Return the block bitmap block of a group + */ +blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_block_bitmap | + (ext2fs_has_feature_64bit(fs->super) ? + (__u64)gdp->bg_block_bitmap_hi << 32 : 0); +} + +/* + * Set the block bitmap block of a group + */ +void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_block_bitmap = blk; + if (ext2fs_has_feature_64bit(fs->super)) + gdp->bg_block_bitmap_hi = (__u64) blk >> 32; +} + +/* + * Return the inode bitmap checksum of a group + */ +__u32 ext2fs_inode_bitmap_checksum(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + __u32 csum; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + csum = gdp->bg_inode_bitmap_csum_lo; + if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) + csum |= ((__u32)gdp->bg_inode_bitmap_csum_hi << 16); + return csum; +} + +/* + * Return the inode bitmap block of a group + */ +blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_inode_bitmap | + (ext2fs_has_feature_64bit(fs->super) ? + (__u64) gdp->bg_inode_bitmap_hi << 32 : 0); +} + +/* + * Set the inode bitmap block of a group + */ +void ext2fs_inode_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_inode_bitmap = blk; + if (ext2fs_has_feature_64bit(fs->super)) + gdp->bg_inode_bitmap_hi = (__u64) blk >> 32; +} + +/* + * Return the inode table block of a group + */ +blk64_t ext2fs_inode_table_loc(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_inode_table | + (ext2fs_has_feature_64bit(fs->super) ? + (__u64) gdp->bg_inode_table_hi << 32 : 0); +} + +/* + * Set the inode table block of a group + */ +void ext2fs_inode_table_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_inode_table = blk; + if (ext2fs_has_feature_64bit(fs->super)) + gdp->bg_inode_table_hi = (__u64) blk >> 32; +} + +/* + * Return the free blocks count of a group + */ +__u32 ext2fs_bg_free_blocks_count(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_free_blocks_count | + (ext2fs_has_feature_64bit(fs->super) ? + (__u32) gdp->bg_free_blocks_count_hi << 16 : 0); +} + +/* + * Set the free blocks count of a group + */ +void ext2fs_bg_free_blocks_count_set(ext2_filsys fs, dgrp_t group, __u32 n) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_free_blocks_count = n; + + if (ext2fs_has_feature_64bit(fs->super)) + gdp->bg_free_blocks_count_hi = (__u32) n >> 16; +} + +/* + * Return the free inodes count of a group + */ +__u32 ext2fs_bg_free_inodes_count(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_free_inodes_count | + (ext2fs_has_feature_64bit(fs->super) ? + (__u32) gdp->bg_free_inodes_count_hi << 16 : 0); +} + +/* + * Set the free inodes count of a group + */ +void ext2fs_bg_free_inodes_count_set(ext2_filsys fs, dgrp_t group, __u32 n) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_free_inodes_count = n; + if (ext2fs_has_feature_64bit(fs->super)) + gdp->bg_free_inodes_count_hi = (__u32) n >> 16; +} + +/* + * Return the used dirs count of a group + */ +__u32 ext2fs_bg_used_dirs_count(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_used_dirs_count | + (ext2fs_has_feature_64bit(fs->super) ? + (__u32) gdp->bg_used_dirs_count_hi << 16 : 0); +} + +/* + * Set the used dirs count of a group + */ +void ext2fs_bg_used_dirs_count_set(ext2_filsys fs, dgrp_t group, __u32 n) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_used_dirs_count = n; + if (ext2fs_has_feature_64bit(fs->super)) + gdp->bg_used_dirs_count_hi = (__u32) n >> 16; +} + +/* + * Return the unused inodes count of a group + */ +__u32 ext2fs_bg_itable_unused(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_itable_unused | + (ext2fs_has_feature_64bit(fs->super) ? + (__u32) gdp->bg_itable_unused_hi << 16 : 0); +} + +/* + * Set the unused inodes count of a group + */ +void ext2fs_bg_itable_unused_set(ext2_filsys fs, dgrp_t group, __u32 n) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_itable_unused = n; + if (ext2fs_has_feature_64bit(fs->super)) + gdp->bg_itable_unused_hi = (__u32) n >> 16; +} + +/* + * Get the flags for this block group + */ +__u16 ext2fs_bg_flags(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_flags; +} + +/* + * Zero out the flags for this block group + */ +void ext2fs_bg_flags_zap(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_flags = 0; + return; +} + +/* + * Get the value of a particular flag for this block group + */ +int ext2fs_bg_flags_test(ext2_filsys fs, dgrp_t group, __u16 bg_flag) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_flags & bg_flag; +} + +/* + * Set a flag or set of flags for this block group + */ +void ext2fs_bg_flags_set(ext2_filsys fs, dgrp_t group, __u16 bg_flags) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_flags |= bg_flags; + return; +} + +/* + * Clear a flag or set of flags for this block group + */ +void ext2fs_bg_flags_clear(ext2_filsys fs, dgrp_t group, __u16 bg_flags) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_flags &= ~bg_flags; + return; +} + +/* + * Get the checksum for this block group + */ +__u16 ext2fs_bg_checksum(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_checksum; +} + +/* + * Set the checksum for this block group to a previously calculated value + */ +void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group, __u16 checksum) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_checksum = checksum; + return; +} + +/* + * Get the acl block of a file + */ +blk64_t ext2fs_file_acl_block(ext2_filsys fs, const struct ext2_inode *inode) +{ + blk64_t blk = inode->i_file_acl; + + if (fs && ext2fs_has_feature_64bit(fs->super)) + blk |= ((__u64) inode->osd2.linux2.l_i_file_acl_high) << 32; + return blk; +} + +/* + * Set the acl block of a file + */ +void ext2fs_file_acl_block_set(ext2_filsys fs, struct ext2_inode *inode, + blk64_t blk) +{ + inode->i_file_acl = blk; + if (fs && ext2fs_has_feature_64bit(fs->super)) + inode->osd2.linux2.l_i_file_acl_high = (__u64) blk >> 32; +} + +/* + * Set the size of the inode + */ +errcode_t ext2fs_inode_size_set(ext2_filsys fs, struct ext2_inode *inode, + ext2_off64_t size) +{ + /* Only regular files get to be larger than 4GB */ + if (!LINUX_S_ISREG(inode->i_mode) && (size >> 32)) + return EXT2_ET_FILE_TOO_BIG; + + /* If we're writing a large file, set the large_file flag */ + if (LINUX_S_ISREG(inode->i_mode) && + ext2fs_needs_large_file_feature(size) && + (!ext2fs_has_feature_large_file(fs->super) || + fs->super->s_rev_level == EXT2_GOOD_OLD_REV)) { + ext2fs_set_feature_large_file(fs->super); + ext2fs_update_dynamic_rev(fs); + ext2fs_mark_super_dirty(fs); + } + + inode->i_size = size & 0xffffffff; + inode->i_size_high = (size >> 32); + + return 0; +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/block.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/block.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,659 @@ +/* + * block.c --- iterate over all blocks in an inode + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +struct block_context { + ext2_filsys fs; + int (*func)(ext2_filsys fs, + blk64_t *blocknr, + e2_blkcnt_t bcount, + blk64_t ref_blk, + int ref_offset, + void *priv_data); + e2_blkcnt_t bcount; + int bsize; + int flags; + errcode_t errcode; + char *ind_buf; + char *dind_buf; + char *tind_buf; + void *priv_data; +}; + +#define check_for_ro_violation_return(ctx, ret) \ + do { \ + if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \ + ((ret) & BLOCK_CHANGED)) { \ + (ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \ + ret |= BLOCK_ABORT | BLOCK_ERROR; \ + return ret; \ + } \ + } while (0) + +#define check_for_ro_violation_goto(ctx, ret, label) \ + do { \ + if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \ + ((ret) & BLOCK_CHANGED)) { \ + (ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \ + ret |= BLOCK_ABORT | BLOCK_ERROR; \ + goto label; \ + } \ + } while (0) + +static int block_iterate_ind(blk_t *ind_block, blk_t ref_block, + int ref_offset, struct block_context *ctx) +{ + int ret = 0, changed = 0; + int i, flags, limit, offset; + blk_t *block_nr; + blk64_t blk64; + + limit = ctx->fs->blocksize >> 2; + if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && + !(ctx->flags & BLOCK_FLAG_DATA_ONLY)) { + blk64 = *ind_block; + ret = (*ctx->func)(ctx->fs, &blk64, + BLOCK_COUNT_IND, ref_block, + ref_offset, ctx->priv_data); + *ind_block = blk64; + } + check_for_ro_violation_return(ctx, ret); + if (!*ind_block || (ret & BLOCK_ABORT)) { + ctx->bcount += limit; + return ret; + } + if (*ind_block >= ext2fs_blocks_count(ctx->fs->super) || + *ind_block < ctx->fs->super->s_first_data_block) { + ctx->errcode = EXT2_ET_BAD_IND_BLOCK; + ret |= BLOCK_ERROR; + return ret; + } + ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block, + ctx->ind_buf); + if (ctx->errcode) { + ret |= BLOCK_ERROR; + return ret; + } + + block_nr = (blk_t *) ctx->ind_buf; + offset = 0; + if (ctx->flags & BLOCK_FLAG_APPEND) { + for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) { + blk64 = *block_nr; + flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount, + *ind_block, offset, + ctx->priv_data); + *block_nr = blk64; + changed |= flags; + if (flags & BLOCK_ABORT) { + ret |= BLOCK_ABORT; + break; + } + offset += sizeof(blk_t); + } + } else { + for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) { + if (*block_nr == 0) + goto skip_sparse; + blk64 = *block_nr; + flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount, + *ind_block, offset, + ctx->priv_data); + *block_nr = blk64; + changed |= flags; + if (flags & BLOCK_ABORT) { + ret |= BLOCK_ABORT; + break; + } + skip_sparse: + offset += sizeof(blk_t); + } + } + check_for_ro_violation_return(ctx, changed); + if (changed & BLOCK_CHANGED) { + ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block, + ctx->ind_buf); + if (ctx->errcode) + ret |= BLOCK_ERROR | BLOCK_ABORT; + } + if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && + !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && + !(ret & BLOCK_ABORT)) { + blk64 = *ind_block; + ret |= (*ctx->func)(ctx->fs, &blk64, + BLOCK_COUNT_IND, ref_block, + ref_offset, ctx->priv_data); + *ind_block = blk64; + } + check_for_ro_violation_return(ctx, ret); + return ret; +} + +static int block_iterate_dind(blk_t *dind_block, blk_t ref_block, + int ref_offset, struct block_context *ctx) +{ + int ret = 0, changed = 0; + int i, flags, limit, offset; + blk_t *block_nr; + blk64_t blk64; + + limit = ctx->fs->blocksize >> 2; + if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE | + BLOCK_FLAG_DATA_ONLY))) { + blk64 = *dind_block; + ret = (*ctx->func)(ctx->fs, &blk64, + BLOCK_COUNT_DIND, ref_block, + ref_offset, ctx->priv_data); + *dind_block = blk64; + } + check_for_ro_violation_return(ctx, ret); + if (!*dind_block || (ret & BLOCK_ABORT)) { + ctx->bcount += limit*limit; + return ret; + } + if (*dind_block >= ext2fs_blocks_count(ctx->fs->super) || + *dind_block < ctx->fs->super->s_first_data_block) { + ctx->errcode = EXT2_ET_BAD_DIND_BLOCK; + ret |= BLOCK_ERROR; + return ret; + } + ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block, + ctx->dind_buf); + if (ctx->errcode) { + ret |= BLOCK_ERROR; + return ret; + } + + block_nr = (blk_t *) ctx->dind_buf; + offset = 0; + if (ctx->flags & BLOCK_FLAG_APPEND) { + for (i = 0; i < limit; i++, block_nr++) { + flags = block_iterate_ind(block_nr, + *dind_block, offset, + ctx); + changed |= flags; + if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { + ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); + break; + } + offset += sizeof(blk_t); + } + } else { + for (i = 0; i < limit; i++, block_nr++) { + if (*block_nr == 0) { + ctx->bcount += limit; + continue; + } + flags = block_iterate_ind(block_nr, + *dind_block, offset, + ctx); + changed |= flags; + if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { + ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); + break; + } + offset += sizeof(blk_t); + } + } + check_for_ro_violation_return(ctx, changed); + if (changed & BLOCK_CHANGED) { + ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block, + ctx->dind_buf); + if (ctx->errcode) + ret |= BLOCK_ERROR | BLOCK_ABORT; + } + if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && + !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && + !(ret & BLOCK_ABORT)) { + blk64 = *dind_block; + ret |= (*ctx->func)(ctx->fs, &blk64, + BLOCK_COUNT_DIND, ref_block, + ref_offset, ctx->priv_data); + *dind_block = blk64; + } + check_for_ro_violation_return(ctx, ret); + return ret; +} + +static int block_iterate_tind(blk_t *tind_block, blk_t ref_block, + int ref_offset, struct block_context *ctx) +{ + int ret = 0, changed = 0; + int i, flags, limit, offset; + blk_t *block_nr; + blk64_t blk64; + + limit = ctx->fs->blocksize >> 2; + if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE | + BLOCK_FLAG_DATA_ONLY))) { + blk64 = *tind_block; + ret = (*ctx->func)(ctx->fs, &blk64, + BLOCK_COUNT_TIND, ref_block, + ref_offset, ctx->priv_data); + *tind_block = blk64; + } + check_for_ro_violation_return(ctx, ret); + if (!*tind_block || (ret & BLOCK_ABORT)) { + ctx->bcount += ((unsigned long long) limit)*limit*limit; + return ret; + } + if (*tind_block >= ext2fs_blocks_count(ctx->fs->super) || + *tind_block < ctx->fs->super->s_first_data_block) { + ctx->errcode = EXT2_ET_BAD_TIND_BLOCK; + ret |= BLOCK_ERROR; + return ret; + } + ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block, + ctx->tind_buf); + if (ctx->errcode) { + ret |= BLOCK_ERROR; + return ret; + } + + block_nr = (blk_t *) ctx->tind_buf; + offset = 0; + if (ctx->flags & BLOCK_FLAG_APPEND) { + for (i = 0; i < limit; i++, block_nr++) { + flags = block_iterate_dind(block_nr, + *tind_block, + offset, ctx); + changed |= flags; + if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { + ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); + break; + } + offset += sizeof(blk_t); + } + } else { + for (i = 0; i < limit; i++, block_nr++) { + if (*block_nr == 0) { + ctx->bcount += limit*limit; + continue; + } + flags = block_iterate_dind(block_nr, + *tind_block, + offset, ctx); + changed |= flags; + if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { + ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); + break; + } + offset += sizeof(blk_t); + } + } + check_for_ro_violation_return(ctx, changed); + if (changed & BLOCK_CHANGED) { + ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block, + ctx->tind_buf); + if (ctx->errcode) + ret |= BLOCK_ERROR | BLOCK_ABORT; + } + if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && + !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && + !(ret & BLOCK_ABORT)) { + blk64 = *tind_block; + ret |= (*ctx->func)(ctx->fs, &blk64, + BLOCK_COUNT_TIND, ref_block, + ref_offset, ctx->priv_data); + *tind_block = blk64; + } + check_for_ro_violation_return(ctx, ret); + return ret; +} + +errcode_t ext2fs_block_iterate3(ext2_filsys fs, + ext2_ino_t ino, + int flags, + char *block_buf, + int (*func)(ext2_filsys fs, + blk64_t *blocknr, + e2_blkcnt_t blockcnt, + blk64_t ref_blk, + int ref_offset, + void *priv_data), + void *priv_data) +{ + int i; + int r, ret = 0; + struct ext2_inode inode; + errcode_t retval; + struct block_context ctx; + int limit; + blk64_t blk64; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + ctx.errcode = ext2fs_read_inode(fs, ino, &inode); + if (ctx.errcode) + return ctx.errcode; + + /* + * An inode with inline data has no blocks over which to + * iterate, so return an error code indicating this fact. + */ + if (inode.i_flags & EXT4_INLINE_DATA_FL) + return EXT2_ET_INLINE_DATA_CANT_ITERATE; + + /* + * Check to see if we need to limit large files + */ + if (flags & BLOCK_FLAG_NO_LARGE) { + if (!LINUX_S_ISDIR(inode.i_mode) && + (inode.i_size_high != 0)) + return EXT2_ET_FILE_TOO_BIG; + } + + limit = fs->blocksize >> 2; + + ctx.fs = fs; + ctx.func = func; + ctx.priv_data = priv_data; + ctx.flags = flags; + ctx.bcount = 0; + if (block_buf) { + ctx.ind_buf = block_buf; + } else { + retval = ext2fs_get_array(3, fs->blocksize, &ctx.ind_buf); + if (retval) + return retval; + } + ctx.dind_buf = ctx.ind_buf + fs->blocksize; + ctx.tind_buf = ctx.dind_buf + fs->blocksize; + + /* + * Iterate over the HURD translator block (if present) + */ + if ((fs->super->s_creator_os == EXT2_OS_HURD) && + !(flags & BLOCK_FLAG_DATA_ONLY)) { + if (inode.osd1.hurd1.h_i_translator) { + blk64 = inode.osd1.hurd1.h_i_translator; + ret |= (*ctx.func)(fs, &blk64, + BLOCK_COUNT_TRANSLATOR, + 0, 0, priv_data); + inode.osd1.hurd1.h_i_translator = (blk_t) blk64; + if (ret & BLOCK_ABORT) + goto abort_exit; + check_for_ro_violation_goto(&ctx, ret, abort_exit); + } + } + + if (inode.i_flags & EXT4_EXTENTS_FL) { + ext2_extent_handle_t handle; + struct ext2fs_extent extent, next; + e2_blkcnt_t blockcnt = 0; + blk64_t blk, new_blk; + int op = EXT2_EXTENT_ROOT; + int uninit; + unsigned int j; + + ctx.errcode = ext2fs_extent_open2(fs, ino, &inode, &handle); + if (ctx.errcode) + goto abort_exit; + + while (1) { + if (op == EXT2_EXTENT_CURRENT) + ctx.errcode = 0; + else + ctx.errcode = ext2fs_extent_get(handle, op, + &extent); + if (ctx.errcode) { + if (ctx.errcode != EXT2_ET_EXTENT_NO_NEXT) + break; + ctx.errcode = 0; + if (!(flags & BLOCK_FLAG_APPEND)) + break; + next_block_set: + blk = 0; + r = (*ctx.func)(fs, &blk, blockcnt, + 0, 0, priv_data); + ret |= r; + check_for_ro_violation_goto(&ctx, ret, + extent_done); + if (r & BLOCK_CHANGED) { + ctx.errcode = + ext2fs_extent_set_bmap(handle, + (blk64_t) blockcnt++, + (blk64_t) blk, 0); + if (ctx.errcode || (ret & BLOCK_ABORT)) + break; + if (blk) + goto next_block_set; + } + break; + } + + op = EXT2_EXTENT_NEXT; + blk = extent.e_pblk; + if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) { + if (ctx.flags & BLOCK_FLAG_DATA_ONLY) + continue; + if ((!(extent.e_flags & + EXT2_EXTENT_FLAGS_SECOND_VISIT) && + !(ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE)) || + ((extent.e_flags & + EXT2_EXTENT_FLAGS_SECOND_VISIT) && + (ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE))) { + ret |= (*ctx.func)(fs, &blk, + -1, 0, 0, priv_data); + if (ret & BLOCK_CHANGED) { + extent.e_pblk = blk; + ctx.errcode = + ext2fs_extent_replace(handle, 0, &extent); + if (ctx.errcode) + break; + } + if (ret & BLOCK_ABORT) + break; + } + continue; + } + uninit = 0; + if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) + uninit = EXT2_EXTENT_SET_BMAP_UNINIT; + + /* + * Get the next extent before we start messing + * with the current extent + */ + retval = ext2fs_extent_get(handle, op, &next); + +#if 0 + printf("lblk %llu pblk %llu len %d blockcnt %llu\n", + extent.e_lblk, extent.e_pblk, + extent.e_len, blockcnt); +#endif + if (extent.e_lblk + extent.e_len <= (blk64_t) blockcnt) + continue; + if (extent.e_lblk > (blk64_t) blockcnt) + blockcnt = extent.e_lblk; + j = blockcnt - extent.e_lblk; + blk += j; + for (blockcnt = extent.e_lblk, j = 0; + j < extent.e_len; + blk++, blockcnt++, j++) { + new_blk = blk; + r = (*ctx.func)(fs, &new_blk, blockcnt, + 0, 0, priv_data); + ret |= r; + check_for_ro_violation_goto(&ctx, ret, + extent_done); + if (r & BLOCK_CHANGED) { + ctx.errcode = + ext2fs_extent_set_bmap(handle, + (blk64_t) blockcnt, + new_blk, uninit); + if (ctx.errcode) + goto extent_done; + } + if (ret & BLOCK_ABORT) + goto extent_done; + } + if (retval == 0) { + extent = next; + op = EXT2_EXTENT_CURRENT; + } + } + + extent_done: + ext2fs_extent_free(handle); + ret |= BLOCK_ERROR; /* ctx.errcode is always valid here */ + goto errout; + } + + /* + * Iterate over normal data blocks + */ + for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) { + if (inode.i_block[i] || (flags & BLOCK_FLAG_APPEND)) { + blk64 = inode.i_block[i]; + ret |= (*ctx.func)(fs, &blk64, ctx.bcount, 0, i, + priv_data); + inode.i_block[i] = (blk_t) blk64; + if (ret & BLOCK_ABORT) + goto abort_exit; + } + } + check_for_ro_violation_goto(&ctx, ret, abort_exit); + if (inode.i_block[EXT2_IND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) { + ret |= block_iterate_ind(&inode.i_block[EXT2_IND_BLOCK], + 0, EXT2_IND_BLOCK, &ctx); + if (ret & BLOCK_ABORT) + goto abort_exit; + } else + ctx.bcount += limit; + if (inode.i_block[EXT2_DIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) { + ret |= block_iterate_dind(&inode.i_block[EXT2_DIND_BLOCK], + 0, EXT2_DIND_BLOCK, &ctx); + if (ret & BLOCK_ABORT) + goto abort_exit; + } else + ctx.bcount += limit * limit; + if (inode.i_block[EXT2_TIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) { + ret |= block_iterate_tind(&inode.i_block[EXT2_TIND_BLOCK], + 0, EXT2_TIND_BLOCK, &ctx); + if (ret & BLOCK_ABORT) + goto abort_exit; + } + +abort_exit: + if (ret & BLOCK_CHANGED) { + retval = ext2fs_write_inode(fs, ino, &inode); + if (retval) { + ret |= BLOCK_ERROR; + ctx.errcode = retval; + } + } +errout: + if (!block_buf) + ext2fs_free_mem(&ctx.ind_buf); + + return (ret & BLOCK_ERROR) ? ctx.errcode : 0; +} + +/* + * Emulate the old ext2fs_block_iterate function! + */ + +struct xlate64 { + int (*func)(ext2_filsys fs, + blk_t *blocknr, + e2_blkcnt_t blockcnt, + blk_t ref_blk, + int ref_offset, + void *priv_data); + void *real_private; +}; + +static int xlate64_func(ext2_filsys fs, blk64_t *blocknr, + e2_blkcnt_t blockcnt, blk64_t ref_blk, + int ref_offset, void *priv_data) +{ + struct xlate64 *xl = (struct xlate64 *) priv_data; + int ret; + blk_t block32 = *blocknr; + + ret = (*xl->func)(fs, &block32, blockcnt, (blk_t) ref_blk, ref_offset, + xl->real_private); + *blocknr = block32; + return ret; +} + +errcode_t ext2fs_block_iterate2(ext2_filsys fs, + ext2_ino_t ino, + int flags, + char *block_buf, + int (*func)(ext2_filsys fs, + blk_t *blocknr, + e2_blkcnt_t blockcnt, + blk_t ref_blk, + int ref_offset, + void *priv_data), + void *priv_data) +{ + struct xlate64 xl; + + xl.real_private = priv_data; + xl.func = func; + + return ext2fs_block_iterate3(fs, ino, flags, block_buf, + xlate64_func, &xl); +} + + +struct xlate { + int (*func)(ext2_filsys fs, + blk_t *blocknr, + int bcount, + void *priv_data); + void *real_private; +}; + +#ifdef __TURBOC__ + #pragma argsused +#endif +static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt, + blk_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct xlate *xl = (struct xlate *) priv_data; + + return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private); +} + +errcode_t ext2fs_block_iterate(ext2_filsys fs, + ext2_ino_t ino, + int flags, + char *block_buf, + int (*func)(ext2_filsys fs, + blk_t *blocknr, + int blockcnt, + void *priv_data), + void *priv_data) +{ + struct xlate xl; + + xl.real_private = priv_data; + xl.func = func; + + return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags, + block_buf, xlate_func, &xl); +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/bmap.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/bmap.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,499 @@ +/* + * bmap.c --- logical to physical block mapping + * + * Copyright (C) 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include + +#include "ext2_fs.h" +#include "ext2fsP.h" + +#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS) +#define _BMAP_INLINE_ __inline__ +#else +#define _BMAP_INLINE_ +#endif + +extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + char *block_buf, int bmap_flags, + blk_t block, blk_t *phys_blk); + +#define inode_bmap(inode, nr) ((inode)->i_block[(nr)]) + +static _BMAP_INLINE_ errcode_t block_ind_bmap(ext2_filsys fs, int flags, + blk_t ind, char *block_buf, + int *blocks_alloc, + blk_t nr, blk_t *ret_blk) +{ + errcode_t retval; + blk_t b; + + if (!ind) { + if (flags & BMAP_SET) + return EXT2_ET_SET_BMAP_NO_IND; + *ret_blk = 0; + return 0; + } + retval = io_channel_read_blk(fs->io, ind, 1, block_buf); + if (retval) + return retval; + + if (flags & BMAP_SET) { + b = *ret_blk; +#ifdef WORDS_BIGENDIAN + b = ext2fs_swab32(b); +#endif + ((blk_t *) block_buf)[nr] = b; + return io_channel_write_blk(fs->io, ind, 1, block_buf); + } + + b = ((blk_t *) block_buf)[nr]; + +#ifdef WORDS_BIGENDIAN + b = ext2fs_swab32(b); +#endif + + if (!b && (flags & BMAP_ALLOC)) { + b = nr ? ext2fs_le32_to_cpu(((blk_t *)block_buf)[nr - 1]) : ind; + retval = ext2fs_alloc_block(fs, b, + block_buf + fs->blocksize, &b); + if (retval) + return retval; + +#ifdef WORDS_BIGENDIAN + ((blk_t *) block_buf)[nr] = ext2fs_swab32(b); +#else + ((blk_t *) block_buf)[nr] = b; +#endif + + retval = io_channel_write_blk(fs->io, ind, 1, block_buf); + if (retval) + return retval; + + (*blocks_alloc)++; + } + + *ret_blk = b; + return 0; +} + +static _BMAP_INLINE_ errcode_t block_dind_bmap(ext2_filsys fs, int flags, + blk_t dind, char *block_buf, + int *blocks_alloc, + blk_t nr, blk_t *ret_blk) +{ + blk_t b = 0; + errcode_t retval; + blk_t addr_per_block; + + addr_per_block = (blk_t) fs->blocksize >> 2; + + retval = block_ind_bmap(fs, flags & ~BMAP_SET, dind, block_buf, + blocks_alloc, nr / addr_per_block, &b); + if (retval) + return retval; + retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc, + nr % addr_per_block, ret_blk); + return retval; +} + +static _BMAP_INLINE_ errcode_t block_tind_bmap(ext2_filsys fs, int flags, + blk_t tind, char *block_buf, + int *blocks_alloc, + blk_t nr, blk_t *ret_blk) +{ + blk_t b = 0; + errcode_t retval; + blk_t addr_per_block; + + addr_per_block = (blk_t) fs->blocksize >> 2; + + retval = block_dind_bmap(fs, flags & ~BMAP_SET, tind, block_buf, + blocks_alloc, nr / addr_per_block, &b); + if (retval) + return retval; + retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc, + nr % addr_per_block, ret_blk); + return retval; +} + +static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + ext2_extent_handle_t handle, + char *block_buf, int bmap_flags, blk64_t block, + int *ret_flags, int *blocks_alloc, + blk64_t *phys_blk); + +static errcode_t implied_cluster_alloc(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + ext2_extent_handle_t handle, + blk64_t lblk, blk64_t *phys_blk) +{ + blk64_t base_block, pblock = 0; + int i; + + if (!ext2fs_has_feature_bigalloc(fs->super)) + return 0; + + base_block = lblk & ~EXT2FS_CLUSTER_MASK(fs); + /* + * Except for the logical block (lblk) that was passed in, search all + * blocks in this logical cluster for a mapping to a physical cluster. + * If any such map exists, calculate the physical block that maps to + * the logical block and return that. + * + * The old code wouldn't even look if (block % cluster_ratio) == 0; + * this is incorrect if we're allocating blocks in reverse order. + */ + for (i = 0; i < EXT2FS_CLUSTER_RATIO(fs); i++) { + if (base_block + i == lblk) + continue; + extent_bmap(fs, ino, inode, handle, 0, 0, + base_block + i, 0, 0, &pblock); + if (pblock) + break; + } + if (pblock == 0) + return 0; + *phys_blk = pblock - i + (lblk - base_block); + return 0; +} + +/* Try to map a logical block to an already-allocated physical cluster. */ +errcode_t ext2fs_map_cluster_block(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t lblk, + blk64_t *pblk) +{ + ext2_extent_handle_t handle; + errcode_t retval; + + /* Need bigalloc and extents to be enabled */ + *pblk = 0; + if (!ext2fs_has_feature_bigalloc(fs->super) || + !(inode->i_flags & EXT4_EXTENTS_FL)) + return 0; + + retval = ext2fs_extent_open2(fs, ino, inode, &handle); + if (retval) + goto out; + + retval = implied_cluster_alloc(fs, ino, inode, handle, lblk, pblk); + if (retval) + goto out2; + +out2: + ext2fs_extent_free(handle); +out: + return retval; +} + +static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + ext2_extent_handle_t handle, + char *block_buf, int bmap_flags, blk64_t block, + int *ret_flags, int *blocks_alloc, + blk64_t *phys_blk) +{ + struct blk_alloc_ctx alloc_ctx; + struct ext2fs_extent extent; + unsigned int offset; + errcode_t retval = 0; + blk64_t blk64 = 0; + int alloc = 0; + int set_flags; + + set_flags = bmap_flags & BMAP_UNINIT ? EXT2_EXTENT_SET_BMAP_UNINIT : 0; + + if (bmap_flags & BMAP_SET) { + retval = ext2fs_extent_set_bmap(handle, block, + *phys_blk, set_flags); + return retval; + } + retval = ext2fs_extent_goto(handle, block); + if (retval) { + /* If the extent is not found, return phys_blk = 0 */ + if (retval == EXT2_ET_EXTENT_NOT_FOUND) { + extent.e_lblk = block; + goto got_block; + } + return retval; + } + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); + if (retval) + return retval; + offset = block - extent.e_lblk; + if (block >= extent.e_lblk && (offset <= extent.e_len)) { + *phys_blk = extent.e_pblk + offset; + if (ret_flags && extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) + *ret_flags |= BMAP_RET_UNINIT; + } +got_block: + if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) { + implied_cluster_alloc(fs, ino, inode, handle, block, &blk64); + if (blk64) + goto set_extent; + retval = extent_bmap(fs, ino, inode, handle, block_buf, + 0, block-1, 0, blocks_alloc, &blk64); + if (retval) + blk64 = ext2fs_find_inode_goal(fs, ino, inode, block); + alloc_ctx.ino = ino; + alloc_ctx.inode = inode; + alloc_ctx.lblk = extent.e_lblk; + alloc_ctx.flags = BLOCK_ALLOC_DATA; + retval = ext2fs_alloc_block3(fs, blk64, block_buf, &blk64, + &alloc_ctx); + if (retval) + return retval; + blk64 &= ~EXT2FS_CLUSTER_MASK(fs); + blk64 += EXT2FS_CLUSTER_MASK(fs) & block; + alloc++; + set_extent: + retval = ext2fs_extent_set_bmap(handle, block, + blk64, set_flags); + if (retval) { + ext2fs_block_alloc_stats2(fs, blk64, -1); + return retval; + } + /* Update inode after setting extent */ + retval = ext2fs_read_inode(fs, ino, inode); + if (retval) + return retval; + *blocks_alloc += alloc; + *phys_blk = blk64; + } + return 0; +} + +int ext2fs_file_block_offset_too_big(ext2_filsys fs, + struct ext2_inode *inode, + blk64_t offset) +{ + blk64_t addr_per_block, max_map_block; + + /* Kernel seems to cut us off at 4294967294 blocks */ + if (offset >= (1ULL << 32) - 1) + return 1; + + if (inode->i_flags & EXT4_EXTENTS_FL) + return 0; + + addr_per_block = fs->blocksize >> 2; + max_map_block = addr_per_block; + max_map_block += addr_per_block * addr_per_block; + max_map_block += addr_per_block * addr_per_block * addr_per_block; + max_map_block += 12; + + return offset >= max_map_block; +} + +errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, + char *block_buf, int bmap_flags, blk64_t block, + int *ret_flags, blk64_t *phys_blk) +{ + struct ext2_inode inode_buf; + ext2_extent_handle_t handle = 0; + blk_t addr_per_block; + blk_t b, blk32; + blk64_t b64; + char *buf = 0; + errcode_t retval = 0; + int blocks_alloc = 0, inode_dirty = 0; + struct blk_alloc_ctx alloc_ctx = { + .ino = ino, + .inode = inode, + .lblk = 0, + .flags = BLOCK_ALLOC_DATA, + }; + + if (!(bmap_flags & BMAP_SET)) + *phys_blk = 0; + + if (ret_flags) + *ret_flags = 0; + + /* Read inode structure if necessary */ + if (!inode) { + retval = ext2fs_read_inode(fs, ino, &inode_buf); + if (retval) + return retval; + inode = &inode_buf; + } + addr_per_block = (blk_t) fs->blocksize >> 2; + + if (ext2fs_file_block_offset_too_big(fs, inode, block)) + return EXT2_ET_FILE_TOO_BIG; + + /* + * If an inode has inline data, that means that it doesn't have + * any blocks and we shouldn't map any blocks for it. + */ + if (inode->i_flags & EXT4_INLINE_DATA_FL) + return EXT2_ET_INLINE_DATA_NO_BLOCK; + + if (!block_buf) { + retval = ext2fs_get_array(2, fs->blocksize, &buf); + if (retval) + return retval; + block_buf = buf; + } + + if (inode->i_flags & EXT4_EXTENTS_FL) { + retval = ext2fs_extent_open2(fs, ino, inode, &handle); + if (retval) + goto done; + retval = extent_bmap(fs, ino, inode, handle, block_buf, + bmap_flags, block, ret_flags, + &blocks_alloc, phys_blk); + goto done; + } + + if (block < EXT2_NDIR_BLOCKS) { + if (bmap_flags & BMAP_SET) { + b = *phys_blk; + inode_bmap(inode, block) = b; + inode_dirty++; + goto done; + } + + *phys_blk = inode_bmap(inode, block); + b = block ? inode_bmap(inode, block - 1) : + ext2fs_find_inode_goal(fs, ino, inode, block); + + if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) { + b64 = b; + retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64, + &alloc_ctx); + b = b64; + if (retval) + goto done; + inode_bmap(inode, block) = b; + blocks_alloc++; + *phys_blk = b; + } + goto done; + } + + /* Indirect block */ + block -= EXT2_NDIR_BLOCKS; + blk32 = *phys_blk; + if (block < addr_per_block) { + b = inode_bmap(inode, EXT2_IND_BLOCK); + if (!b) { + if (!(bmap_flags & BMAP_ALLOC)) { + if (bmap_flags & BMAP_SET) + retval = EXT2_ET_SET_BMAP_NO_IND; + goto done; + } + + b = inode_bmap(inode, EXT2_IND_BLOCK-1); + b64 = b; + retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64, + &alloc_ctx); + b = b64; + if (retval) + goto done; + inode_bmap(inode, EXT2_IND_BLOCK) = b; + blocks_alloc++; + } + retval = block_ind_bmap(fs, bmap_flags, b, block_buf, + &blocks_alloc, block, &blk32); + if (retval == 0) + *phys_blk = blk32; + goto done; + } + + /* Doubly indirect block */ + block -= addr_per_block; + if (block < addr_per_block * addr_per_block) { + b = inode_bmap(inode, EXT2_DIND_BLOCK); + if (!b) { + if (!(bmap_flags & BMAP_ALLOC)) { + if (bmap_flags & BMAP_SET) + retval = EXT2_ET_SET_BMAP_NO_IND; + goto done; + } + + b = inode_bmap(inode, EXT2_IND_BLOCK); + b64 = b; + retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64, + &alloc_ctx); + b = b64; + if (retval) + goto done; + inode_bmap(inode, EXT2_DIND_BLOCK) = b; + blocks_alloc++; + } + retval = block_dind_bmap(fs, bmap_flags, b, block_buf, + &blocks_alloc, block, &blk32); + if (retval == 0) + *phys_blk = blk32; + goto done; + } + + /* Triply indirect block */ + block -= addr_per_block * addr_per_block; + b = inode_bmap(inode, EXT2_TIND_BLOCK); + if (!b) { + if (!(bmap_flags & BMAP_ALLOC)) { + if (bmap_flags & BMAP_SET) + retval = EXT2_ET_SET_BMAP_NO_IND; + goto done; + } + + b = inode_bmap(inode, EXT2_DIND_BLOCK); + b64 = b; + retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64, + &alloc_ctx); + b = b64; + if (retval) + goto done; + inode_bmap(inode, EXT2_TIND_BLOCK) = b; + blocks_alloc++; + } + retval = block_tind_bmap(fs, bmap_flags, b, block_buf, + &blocks_alloc, block, &blk32); + if (retval == 0) + *phys_blk = blk32; +done: + if (*phys_blk && retval == 0 && (bmap_flags & BMAP_ZERO)) + retval = ext2fs_zero_blocks2(fs, *phys_blk, 1, NULL, NULL); + if (buf) + ext2fs_free_mem(&buf); + if (handle) + ext2fs_extent_free(handle); + if ((retval == 0) && (blocks_alloc || inode_dirty)) { + ext2fs_iblk_add_blocks(fs, inode, blocks_alloc); + retval = ext2fs_write_inode(fs, ino, inode); + } + return retval; +} + +errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, + char *block_buf, int bmap_flags, blk_t block, + blk_t *phys_blk) +{ + errcode_t ret; + blk64_t ret_blk = *phys_blk; + + ret = ext2fs_bmap2(fs, ino, inode, block_buf, bmap_flags, block, + 0, &ret_blk); + if (ret) + return ret; + if (ret_blk >= ((long long) 1 << 32)) + return EOVERFLOW; + *phys_blk = ret_blk; + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/bmap64.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/bmap64.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,104 @@ +/* + * bmap64.h --- 64-bit bitmap structure + * + * Copyright (C) 2007, 2008 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +struct ext2_bmap_statistics { + int type; + struct timeval created; + +#ifdef ENABLE_BMAP_STATS_OPS + unsigned long copy_count; + unsigned long resize_count; + unsigned long mark_count; + unsigned long unmark_count; + unsigned long test_count; + unsigned long mark_ext_count; + unsigned long unmark_ext_count; + unsigned long test_ext_count; + unsigned long set_range_count; + unsigned long get_range_count; + unsigned long clear_count; + + blk64_t last_marked; + blk64_t last_tested; + blk64_t mark_back; + blk64_t test_back; + + unsigned long mark_seq; + unsigned long test_seq; +#endif /* ENABLE_BMAP_STATS_OPS */ +}; + + +struct ext2fs_struct_generic_bitmap { + errcode_t magic; + ext2_filsys fs; + struct ext2_bitmap_ops *bitmap_ops; + int flags; + __u64 start, end; + __u64 real_end; + int cluster_bits; + char *description; + void *private; + errcode_t base_error_code; +#ifdef ENABLE_BMAP_STATS + struct ext2_bmap_statistics stats; +#endif +}; + +#define EXT2FS_IS_32_BITMAP(bmap) \ + (((bmap)->magic == EXT2_ET_MAGIC_GENERIC_BITMAP) || \ + ((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP) || \ + ((bmap)->magic == EXT2_ET_MAGIC_INODE_BITMAP)) + +#define EXT2FS_IS_64_BITMAP(bmap) \ + (((bmap)->magic == EXT2_ET_MAGIC_GENERIC_BITMAP64) || \ + ((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP64) || \ + ((bmap)->magic == EXT2_ET_MAGIC_INODE_BITMAP64)) + +struct ext2_bitmap_ops { + int type; + /* Generic bmap operators */ + errcode_t (*new_bmap)(ext2_filsys fs, ext2fs_generic_bitmap bmap); + void (*free_bmap)(ext2fs_generic_bitmap bitmap); + errcode_t (*copy_bmap)(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap dest); + errcode_t (*resize_bmap)(ext2fs_generic_bitmap bitmap, + __u64 new_end, + __u64 new_real_end); + /* bit set/test operators */ + int (*mark_bmap)(ext2fs_generic_bitmap bitmap, __u64 arg); + int (*unmark_bmap)(ext2fs_generic_bitmap bitmap, __u64 arg); + int (*test_bmap)(ext2fs_generic_bitmap bitmap, __u64 arg); + void (*mark_bmap_extent)(ext2fs_generic_bitmap bitmap, __u64 arg, + unsigned int num); + void (*unmark_bmap_extent)(ext2fs_generic_bitmap bitmap, __u64 arg, + unsigned int num); + int (*test_clear_bmap_extent)(ext2fs_generic_bitmap bitmap, + __u64 arg, unsigned int num); + errcode_t (*set_bmap_range)(ext2fs_generic_bitmap bitmap, + __u64 start, size_t num, void *in); + errcode_t (*get_bmap_range)(ext2fs_generic_bitmap bitmap, + __u64 start, size_t num, void *out); + void (*clear_bmap)(ext2fs_generic_bitmap bitmap); + void (*print_stats)(ext2fs_generic_bitmap); + + /* Find the first zero bit between start and end, inclusive. + * May be NULL, in which case a generic function is used. */ + errcode_t (*find_first_zero)(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out); + /* Find the first set bit between start and end, inclusive. + * May be NULL, in which case a generic function is used. */ + errcode_t (*find_first_set)(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out); +}; + +extern struct ext2_bitmap_ops ext2fs_blkmap64_bitarray; +extern struct ext2_bitmap_ops ext2fs_blkmap64_rbtree; diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/brel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/brel.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,86 @@ +/* + * brel.h + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +struct ext2_block_relocate_entry { + blk64_t new; + __s16 offset; + __u16 flags; + union { + blk64_t block_ref; + ext2_ino_t inode_ref; + } owner; +}; + +#define RELOCATE_TYPE_REF 0x0007 +#define RELOCATE_BLOCK_REF 0x0001 +#define RELOCATE_INODE_REF 0x0002 + +typedef struct ext2_block_relocation_table *ext2_brel; + +struct ext2_block_relocation_table { + __u32 magic; + char *name; + blk64_t current; + void *priv_data; + + /* + * Add a block relocation entry. + */ + errcode_t (*put)(ext2_brel brel, blk64_t old, + struct ext2_block_relocate_entry *ent); + + /* + * Get a block relocation entry. + */ + errcode_t (*get)(ext2_brel brel, blk64_t old, + struct ext2_block_relocate_entry *ent); + + /* + * Initialize for iterating over the block relocation entries. + */ + errcode_t (*start_iter)(ext2_brel brel); + + /* + * The iterator function for the inode relocation entries. + * Returns an inode number of 0 when out of entries. + */ + errcode_t (*next)(ext2_brel brel, blk64_t *old, + struct ext2_block_relocate_entry *ent); + + /* + * Move the inode relocation table from one block number to + * another. + */ + errcode_t (*move)(ext2_brel brel, blk64_t old, blk_t new); + + /* + * Remove a block relocation entry. + */ + errcode_t (*delete)(ext2_brel brel, blk64_t old); + + + /* + * Free the block relocation table. + */ + errcode_t (*free)(ext2_brel brel); +}; + +errcode_t ext2fs_brel_memarray_create(char *name, blk64_t max_block, + ext2_brel *brel); + +#define ext2fs_brel_put(brel, old, ent) ((brel)->put((brel), old, ent)) +#define ext2fs_brel_get(brel, old, ent) ((brel)->get((brel), old, ent)) +#define ext2fs_brel_start_iter(brel) ((brel)->start_iter((brel))) +#define ext2fs_brel_next(brel, old, ent) ((brel)->next((brel), old, ent)) +#define ext2fs_brel_move(brel, old, new) ((brel)->move((brel), old, new)) +#define ext2fs_brel_delete(brel, old) ((brel)->delete((brel), old)) +#define ext2fs_brel_free(brel) ((brel)->free((brel))) + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/check_desc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/check_desc.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,104 @@ +/* + * check_desc.c --- Check the group descriptors of an ext2 filesystem + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +/* + * This routine sanity checks the group descriptors + */ +errcode_t ext2fs_check_desc(ext2_filsys fs) +{ + ext2fs_block_bitmap bmap; + errcode_t retval; + dgrp_t i; + blk64_t first_block = fs->super->s_first_data_block; + blk64_t last_block = ext2fs_blocks_count(fs->super)-1; + blk64_t blk, b; + unsigned int j; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (EXT2_DESC_SIZE(fs->super) & (EXT2_DESC_SIZE(fs->super) - 1)) + return EXT2_ET_BAD_DESC_SIZE; + + retval = ext2fs_allocate_subcluster_bitmap(fs, "check_desc map", &bmap); + if (retval) + return retval; + + for (i = 0; i < fs->group_desc_count; i++) + ext2fs_reserve_super_and_bgd(fs, i, bmap); + + for (i = 0; i < fs->group_desc_count; i++) { + if (!ext2fs_has_feature_flex_bg(fs->super)) { + first_block = ext2fs_group_first_block2(fs, i); + last_block = ext2fs_group_last_block2(fs, i); + } + + /* + * Check to make sure the block bitmap for group is sane + */ + blk = ext2fs_block_bitmap_loc(fs, i); + if (blk < first_block || blk > last_block || + ext2fs_test_block_bitmap2(bmap, blk)) { + retval = EXT2_ET_GDESC_BAD_BLOCK_MAP; + goto errout; + } + ext2fs_mark_block_bitmap2(bmap, blk); + + /* + * Check to make sure the inode bitmap for group is sane + */ + blk = ext2fs_inode_bitmap_loc(fs, i); + if (blk < first_block || blk > last_block || + ext2fs_test_block_bitmap2(bmap, blk)) { + retval = EXT2_ET_GDESC_BAD_INODE_MAP; + goto errout; + } + ext2fs_mark_block_bitmap2(bmap, blk); + + /* + * Check to make sure the inode table for group is sane + */ + blk = ext2fs_inode_table_loc(fs, i); + if (blk < first_block || + ((blk + fs->inode_blocks_per_group - 1) > last_block)) { + retval = EXT2_ET_GDESC_BAD_INODE_TABLE; + goto errout; + } + for (j = 0, b = blk; j < fs->inode_blocks_per_group; + j++, b++) { + if (ext2fs_test_block_bitmap2(bmap, b)) { + retval = EXT2_ET_GDESC_BAD_INODE_TABLE; + goto errout; + } + ext2fs_mark_block_bitmap2(bmap, b); + } + } +errout: + ext2fs_free_block_bitmap(bmap); + return retval; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/closefs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/closefs.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,512 @@ +/* + * closefs.c --- close an ext2 filesystem + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "ext2_fs.h" +#include "ext2fsP.h" + +static int test_root(unsigned int a, unsigned int b) +{ + while (1) { + if (a < b) + return 0; + if (a == b) + return 1; + if (a % b) + return 0; + a = a / b; + } +} + +int ext2fs_bg_has_super(ext2_filsys fs, dgrp_t group) +{ + if (group == 0) + return 1; + if (ext2fs_has_feature_sparse_super2(fs->super)) { + if (group == fs->super->s_backup_bgs[0] || + group == fs->super->s_backup_bgs[1]) + return 1; + return 0; + } + if ((group <= 1) || !ext2fs_has_feature_sparse_super(fs->super)) + return 1; + if (!(group & 1)) + return 0; + if (test_root(group, 3) || (test_root(group, 5)) || + test_root(group, 7)) + return 1; + + return 0; +} + +/* + * ext2fs_super_and_bgd_loc2() + * @fs: ext2 fs pointer + * @group given block group + * @ret_super_blk: if !NULL, returns super block location + * @ret_old_desc_blk: if !NULL, returns location of the old block + * group descriptor + * @ret_new_desc_blk: if !NULL, returns location of meta_bg block + * group descriptor + * @ret_used_blks: if !NULL, returns number of blocks used by + * super block and group_descriptors. + * + * Returns errcode_t of 0 + */ +errcode_t ext2fs_super_and_bgd_loc2(ext2_filsys fs, + dgrp_t group, + blk64_t *ret_super_blk, + blk64_t *ret_old_desc_blk, + blk64_t *ret_new_desc_blk, + blk_t *ret_used_blks) +{ + blk64_t group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0; + unsigned int meta_bg, meta_bg_size; + blk_t numblocks = 0; + blk64_t old_desc_blocks; + int has_super; + + group_block = ext2fs_group_first_block2(fs, group); + if (group_block == 0 && fs->blocksize == 1024) + group_block = 1; /* Deal with 1024 blocksize && bigalloc */ + + if (ext2fs_has_feature_meta_bg(fs->super)) + old_desc_blocks = fs->super->s_first_meta_bg; + else + old_desc_blocks = + fs->desc_blocks + fs->super->s_reserved_gdt_blocks; + + has_super = ext2fs_bg_has_super(fs, group); + + if (has_super) { + super_blk = group_block; + numblocks++; + } + meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super); + meta_bg = group / meta_bg_size; + + if (!ext2fs_has_feature_meta_bg(fs->super) || + (meta_bg < fs->super->s_first_meta_bg)) { + if (has_super) { + old_desc_blk = group_block + 1; + numblocks += old_desc_blocks; + } + } else { + if (((group % meta_bg_size) == 0) || + ((group % meta_bg_size) == 1) || + ((group % meta_bg_size) == (meta_bg_size-1))) { + if (has_super) + has_super = 1; + new_desc_blk = group_block + has_super; + numblocks++; + } + } + + if (ret_super_blk) + *ret_super_blk = super_blk; + if (ret_old_desc_blk) + *ret_old_desc_blk = old_desc_blk; + if (ret_new_desc_blk) + *ret_new_desc_blk = new_desc_blk; + if (ret_used_blks) + *ret_used_blks = numblocks; + + return 0; +} + +/* + * This function returns the location of the superblock, block group + * descriptors for a given block group. It currently returns the + * number of free blocks assuming that inode table and allocation + * bitmaps will be in the group. This is not necessarily the case + * when the flex_bg feature is enabled, so callers should take care! + * It was only really intended for use by mke2fs, and even there it's + * not that useful. + * + * The ext2fs_super_and_bgd_loc2() function is 64-bit block number + * capable and returns the number of blocks used by super block and + * group descriptors. + */ +int ext2fs_super_and_bgd_loc(ext2_filsys fs, + dgrp_t group, + blk_t *ret_super_blk, + blk_t *ret_old_desc_blk, + blk_t *ret_new_desc_blk, + int *ret_meta_bg) +{ + blk64_t ret_super_blk2; + blk64_t ret_old_desc_blk2; + blk64_t ret_new_desc_blk2; + blk_t ret_used_blks; + blk_t numblocks; + unsigned int meta_bg_size; + + ext2fs_super_and_bgd_loc2(fs, group, &ret_super_blk2, + &ret_old_desc_blk2, + &ret_new_desc_blk2, + &ret_used_blks); + + numblocks = ext2fs_group_blocks_count(fs, group); + + if (ret_super_blk) + *ret_super_blk = (blk_t)ret_super_blk2; + if (ret_old_desc_blk) + *ret_old_desc_blk = (blk_t)ret_old_desc_blk2; + if (ret_new_desc_blk) + *ret_new_desc_blk = (blk_t)ret_new_desc_blk2; + if (ret_meta_bg) { + meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super); + *ret_meta_bg = group / meta_bg_size; + } + + numblocks -= 2 + fs->inode_blocks_per_group + ret_used_blks; + + return numblocks; +} + +/* + * This function forces out the primary superblock. We need to only + * write out those fields which we have changed, since if the + * filesystem is mounted, it may have changed some of the other + * fields. + * + * It takes as input a superblock which has already been byte swapped + * (if necessary). + * + */ +static errcode_t write_primary_superblock(ext2_filsys fs, + struct ext2_super_block *super) +{ + __u16 *old_super, *new_super; + int check_idx, write_idx, size; + errcode_t retval; + + if (!fs->io->manager->write_byte || !fs->orig_super) { + fallback: + io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET); + retval = io_channel_write_blk64(fs->io, 1, -SUPERBLOCK_SIZE, + super); + io_channel_set_blksize(fs->io, fs->blocksize); + return retval; + } + + old_super = (__u16 *) fs->orig_super; + new_super = (__u16 *) super; + + for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) { + if (old_super[check_idx] == new_super[check_idx]) + continue; + write_idx = check_idx; + for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++) + if (old_super[check_idx] == new_super[check_idx]) + break; + size = 2 * (check_idx - write_idx); +#if 0 + printf("Writing %d bytes starting at %d\n", + size, write_idx*2); +#endif + retval = io_channel_write_byte(fs->io, + SUPERBLOCK_OFFSET + (2 * write_idx), size, + new_super + write_idx); + if (retval == EXT2_ET_UNIMPLEMENTED) + goto fallback; + if (retval) + return retval; + } + memcpy(fs->orig_super, super, SUPERBLOCK_SIZE); + return 0; +} + + +/* + * Updates the revision to EXT2_DYNAMIC_REV + */ +void ext2fs_update_dynamic_rev(ext2_filsys fs) +{ + struct ext2_super_block *sb = fs->super; + + if (sb->s_rev_level > EXT2_GOOD_OLD_REV) + return; + + sb->s_rev_level = EXT2_DYNAMIC_REV; + sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; + sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; + /* s_uuid is handled by e2fsck already */ + /* other fields should be left alone */ +} + +static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group, + blk64_t group_block, + struct ext2_super_block *super_shadow) +{ + errcode_t retval; + dgrp_t sgrp = group; + + if (sgrp > ((1 << 16) - 1)) + sgrp = (1 << 16) - 1; + + super_shadow->s_block_group_nr = ext2fs_cpu_to_le16(sgrp); + + retval = ext2fs_superblock_csum_set(fs, super_shadow); + if (retval) + return retval; + + return io_channel_write_blk64(fs->io, group_block, -SUPERBLOCK_SIZE, + super_shadow); +} + +errcode_t ext2fs_flush(ext2_filsys fs) +{ + return ext2fs_flush2(fs, 0); +} + +errcode_t ext2fs_flush2(ext2_filsys fs, int flags) +{ + dgrp_t i; + errcode_t retval; + unsigned long fs_state; + __u32 feature_incompat; + struct ext2_super_block *super_shadow = 0; + struct opaque_ext2_group_desc *group_shadow = 0; +#ifdef WORDS_BIGENDIAN + struct ext2_group_desc *gdp; + dgrp_t j; +#endif + char *group_ptr; + blk64_t old_desc_blocks; + struct ext2fs_numeric_progress_struct progress; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + fs_state = fs->super->s_state; + feature_incompat = fs->super->s_feature_incompat; + + fs->super->s_wtime = fs->now ? fs->now : time(NULL); + fs->super->s_block_group_nr = 0; + + /* + * If the write_bitmaps() function is present, call it to + * flush the bitmaps. This is done this way so that a simple + * program that doesn't mess with the bitmaps doesn't need to + * drag in the bitmaps.c code. + * + * Bitmap checksums live in the group descriptor, so the + * bitmaps need to be written before the descriptors. + */ + if (fs->write_bitmaps) { + retval = fs->write_bitmaps(fs); + if (retval) + goto errout; + } + + /* + * Set the state of the FS to be non-valid. (The state has + * already been backed up earlier, and will be restored after + * we write out the backup superblocks.) + */ + fs->super->s_state &= ~EXT2_VALID_FS; + ext2fs_clear_feature_journal_needs_recovery(fs->super); + + /* Byte swap the superblock and the group descriptors if necessary */ +#ifdef WORDS_BIGENDIAN + retval = EXT2_ET_NO_MEMORY; + retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow); + if (retval) + goto errout; + retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize, + &group_shadow); + if (retval) + goto errout; + memcpy(super_shadow, fs->super, sizeof(struct ext2_super_block)); + memcpy(group_shadow, fs->group_desc, (size_t) fs->blocksize * + fs->desc_blocks); + + ext2fs_swap_super(super_shadow); + for (j = 0; j < fs->group_desc_count; j++) { + gdp = ext2fs_group_desc(fs, group_shadow, j); + ext2fs_swap_group_desc2(fs, gdp); + } +#else + super_shadow = fs->super; + group_shadow = fs->group_desc; +#endif + + /* + * If this is an external journal device, don't write out the + * block group descriptors or any of the backup superblocks + */ + if (ext2fs_has_feature_journal_dev(fs->super)) + goto write_primary_superblock_only; + + /* + * Write out the master group descriptors, and the backup + * superblocks and group descriptors. + */ + group_ptr = (char *) group_shadow; + if (ext2fs_has_feature_meta_bg(fs->super)) { + old_desc_blocks = fs->super->s_first_meta_bg; + if (old_desc_blocks > fs->desc_blocks) + old_desc_blocks = fs->desc_blocks; + } else + old_desc_blocks = fs->desc_blocks; + + if (fs->progress_ops && fs->progress_ops->init) + (fs->progress_ops->init)(fs, &progress, NULL, + fs->group_desc_count); + + + for (i = 0; i < fs->group_desc_count; i++) { + blk64_t super_blk, old_desc_blk, new_desc_blk; + + if (fs->progress_ops && fs->progress_ops->update) + (fs->progress_ops->update)(fs, &progress, i); + ext2fs_super_and_bgd_loc2(fs, i, &super_blk, &old_desc_blk, + &new_desc_blk, 0); + + if (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) &&i && super_blk) { + retval = write_backup_super(fs, i, super_blk, + super_shadow); + if (retval) + goto errout; + } + if (fs->flags & EXT2_FLAG_SUPER_ONLY) + continue; + if ((old_desc_blk) && + (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) || (i == 0))) { + retval = io_channel_write_blk64(fs->io, + old_desc_blk, old_desc_blocks, group_ptr); + if (retval) + goto errout; + } + if (new_desc_blk) { + int meta_bg = i / EXT2_DESC_PER_BLOCK(fs->super); + + retval = io_channel_write_blk64(fs->io, new_desc_blk, + 1, group_ptr + (meta_bg*fs->blocksize)); + if (retval) + goto errout; + } + } + + if (fs->progress_ops && fs->progress_ops->close) + (fs->progress_ops->close)(fs, &progress, NULL); + +write_primary_superblock_only: + /* + * Write out master superblock. This has to be done + * separately, since it is located at a fixed location + * (SUPERBLOCK_OFFSET). We flush all other pending changes + * out to disk first, just to avoid a race condition with an + * insy-tinsy window.... + */ + + fs->super->s_block_group_nr = 0; + fs->super->s_state = fs_state; + fs->super->s_feature_incompat = feature_incompat; +#ifdef WORDS_BIGENDIAN + *super_shadow = *fs->super; + ext2fs_swap_super(super_shadow); +#endif + + retval = ext2fs_superblock_csum_set(fs, super_shadow); + if (retval) + return retval; + + if (!(flags & EXT2_FLAG_FLUSH_NO_SYNC)) { + retval = io_channel_flush(fs->io); + if (retval) + goto errout; + } + retval = write_primary_superblock(fs, super_shadow); + if (retval) + goto errout; + + fs->flags &= ~EXT2_FLAG_DIRTY; + + if (!(flags & EXT2_FLAG_FLUSH_NO_SYNC)) { + retval = io_channel_flush(fs->io); + if (retval) + goto errout; + } +errout: + fs->super->s_state = fs_state; +#ifdef WORDS_BIGENDIAN + if (super_shadow) + ext2fs_free_mem(&super_shadow); + if (group_shadow) + ext2fs_free_mem(&group_shadow); +#endif + return retval; +} + +errcode_t ext2fs_close_free(ext2_filsys *fs_ptr) +{ + errcode_t ret; + ext2_filsys fs = *fs_ptr; + + ret = ext2fs_close2(fs, 0); + if (ret) + ext2fs_free(fs); + *fs_ptr = NULL; + return ret; +} + +errcode_t ext2fs_close(ext2_filsys fs) +{ + return ext2fs_close2(fs, 0); +} + +errcode_t ext2fs_close2(ext2_filsys fs, int flags) +{ + errcode_t retval; + int meta_blks; + io_stats stats = 0; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (fs->write_bitmaps) { + retval = fs->write_bitmaps(fs); + if (retval) + return retval; + } + if (fs->super->s_kbytes_written && + fs->io->manager->get_stats) + fs->io->manager->get_stats(fs->io, &stats); + if (stats && stats->bytes_written && (fs->flags & EXT2_FLAG_RW)) { + fs->super->s_kbytes_written += stats->bytes_written >> 10; + meta_blks = fs->desc_blocks + 1; + if (!(fs->flags & EXT2_FLAG_SUPER_ONLY)) + fs->super->s_kbytes_written += meta_blks / + (fs->blocksize / 1024); + if ((fs->flags & EXT2_FLAG_DIRTY) == 0) + fs->flags |= EXT2_FLAG_SUPER_ONLY | EXT2_FLAG_DIRTY; + } + if (fs->flags & EXT2_FLAG_DIRTY) { + retval = ext2fs_flush2(fs, flags); + if (retval) + return retval; + } + + retval = ext2fs_mmp_stop(fs); + if (retval) + return retval; + + ext2fs_free(fs); + return 0; +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/crc16.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/crc16.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,74 @@ +/* + * crc16.c + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include "config.h" +#if HAVE_SYS_TYPES_H +#include +#endif +#include + +#include "crc16.h" + +/** CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1) */ +static __u16 const crc16_table[256] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 +}; + +/** + * Compute the CRC-16 for the data buffer + * + * @param crc previous CRC value + * @param buffer data pointer + * @param len number of bytes in the buffer + * @return the updated CRC value + */ +crc16_t ext2fs_crc16(crc16_t crc, const void *buffer, unsigned int len) +{ + const unsigned char *cp = buffer; + + while (len--) + /* + * for an unknown reason, PPC treats __u16 as signed + * and keeps doing sign extension on the value. + * Instead, use only the low 16 bits of an unsigned + * int for holding the CRC value to avoid this. + */ + crc = (((crc >> 8) & 0xffU) ^ + crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU; + return crc; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/crc16.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/crc16.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,26 @@ +/* + * crc16.h - CRC-16 routine + * + * Implements the standard CRC-16: + * Width 16 + * Poly 0x8005 (x16 + x15 + x2 + 1) + * Init 0 + * + * Copyright (c) 2005 Ben Gardner + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#ifndef __CRC16_H +#define __CRC16_H + +/* for an unknown reason, PPC treats __u16 as signed and keeps doing sign + * extension on the value. Instead, use only the low 16 bits of an + * unsigned int for holding the CRC value to avoid this. + */ +typedef unsigned int crc16_t; + +extern crc16_t ext2fs_crc16(crc16_t crc, const void *buffer, unsigned int len); + +#endif /* __CRC16_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/crc32c.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/crc32c.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,932 @@ +/* + * crc32c.c + * + * August 26, 2011 Darrick J. Wong + * Reuse Bob Pearson's slice-by-8 implementation for e2fsprogs. + * + * July 20, 2011 Bob Pearson + * added slice by 8 algorithm to the existing conventional and + * slice by 4 algorithms. + * + * 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. + */ +#include "config.h" +#include +#include +#include +#define min(x, y) ((x) > (y) ? (y) : (x)) +#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1) +#define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) +#define PTR_ALIGN(p, a) ((__typeof__(p))ALIGN((unsigned long)(p), (a))) +#include "crc32c_defs.h" + +#include "ext2fs.h" +#ifdef WORDS_BIGENDIAN +#define __constant_cpu_to_le32(x) ___constant_swab32((x)) +#define __constant_cpu_to_be32(x) (x) +#define __be32_to_cpu(x) (x) +#define __cpu_to_be32(x) (x) +#define __cpu_to_le32(x) (ext2fs_cpu_to_le32((x))) +#define __le32_to_cpu(x) (ext2fs_le32_to_cpu((x))) +#else +#define __constant_cpu_to_le32(x) (x) +#define __constant_cpu_to_be32(x) ___constant_swab32((x)) +#define __be32_to_cpu(x) (ext2fs_be32_to_cpu((x))) +#define __cpu_to_be32(x) (ext2fs_cpu_to_be32((x))) +#define __cpu_to_le32(x) (x) +#define __le32_to_cpu(x) (x) +#endif + +#if CRC_LE_BITS > 8 +# define tole(x) __constant_cpu_to_le32(x) +#else +# define tole(x) (x) +#endif + +#if CRC_BE_BITS > 8 +# define tobe(x) __constant_cpu_to_be32(x) +#else +# define tobe(x) (x) +#endif + +#include "crc32c_table.h" + +#if CRC_LE_BITS > 8 || CRC_BE_BITS > 8 + +/* implements slicing-by-4 or slicing-by-8 algorithm */ +static inline uint32_t +crc32_body(uint32_t crc, unsigned char const *buf, size_t len, + const uint32_t (*tab)[256]) +{ +# ifndef WORDS_BIGENDIAN +# 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]) +# else +# 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]) +# endif + const uint32_t *b; + size_t rem_len; + const uint32_t *t0 = tab[0], *t1 = tab[1], *t2 = tab[2], *t3 = tab[3]; + const uint32_t *t4 = tab[4], *t5 = tab[5], *t6 = tab[6], *t7 = tab[7]; + uint32_t q; + + /* Align it */ + if (unlikely((uintptr_t)buf & 3 && len)) { + do { + DO_CRC(*buf++); + } while ((--len) && ((uintptr_t)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 uint32_t *)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) { + const uint8_t *p = (const uint8_t *)(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 uint32_t crc32_le_generic(uint32_t crc, unsigned char const *p, + size_t len, const uint32_t (*tab)[256], + uint32_t polynomial EXT2FS_ATTR((unused))) +{ +#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 = __cpu_to_le32(crc); + crc = crc32_body(crc, p, len, tab); + crc = __le32_to_cpu(crc); +#endif + return crc; +} + +uint32_t ext2fs_crc32c_le(uint32_t crc, unsigned char const *p, size_t len) +{ + return crc32_le_generic(crc, p, len, crc32ctable_le, CRC32C_POLY_LE); +} + +/** + * crc32_be() - Calculate bitwise big-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 uint32_t crc32_be_generic(uint32_t crc, unsigned char const *p, + size_t len, const uint32_t (*tab)[256], + uint32_t polynomial EXT2FS_ATTR((unused))) +{ +#if CRC_BE_BITS == 1 + int i; + while (len--) { + crc ^= *p++ << 24; + for (i = 0; i < 8; i++) + crc = + (crc << 1) ^ ((crc & 0x80000000) ? polynomial : + 0); + } +# elif CRC_BE_BITS == 2 + while (len--) { + crc ^= *p++ << 24; + crc = (crc << 2) ^ tab[0][crc >> 30]; + crc = (crc << 2) ^ tab[0][crc >> 30]; + crc = (crc << 2) ^ tab[0][crc >> 30]; + crc = (crc << 2) ^ tab[0][crc >> 30]; + } +# elif CRC_BE_BITS == 4 + while (len--) { + crc ^= *p++ << 24; + crc = (crc << 4) ^ tab[0][crc >> 28]; + crc = (crc << 4) ^ tab[0][crc >> 28]; + } +# elif CRC_BE_BITS == 8 + while (len--) { + crc ^= *p++ << 24; + crc = (crc << 8) ^ tab[0][crc >> 24]; + } +# else + crc = __cpu_to_be32(crc); + crc = crc32_body(crc, p, len, tab); + crc = __be32_to_cpu(crc); +# endif + return crc; +} + +uint32_t ext2fs_crc32_be(uint32_t crc, unsigned char const *p, size_t len) +{ + return crc32_be_generic(crc, p, len, crc32table_be, CRCPOLY_BE); +} + +#ifdef UNITTEST +static uint8_t test_buf[] = { + 0xd9, 0xd7, 0x6a, 0x13, 0x3a, 0xb1, 0x05, 0x48, + 0xda, 0xad, 0x14, 0xbd, 0x03, 0x3a, 0x58, 0x5e, + 0x6e, 0xd1, 0x56, 0xc9, 0x2e, 0xc4, 0xcb, 0x6b, + 0xe8, 0x77, 0x52, 0x37, 0x4e, 0x0f, 0x55, 0xd2, + 0x12, 0x65, 0x90, 0xc2, 0x41, 0x49, 0x81, 0x01, + 0xf5, 0x01, 0xeb, 0x2d, 0x78, 0x74, 0x23, 0x5d, + 0x84, 0x5c, 0x81, 0x92, 0x21, 0xe9, 0x8d, 0x1d, + 0x89, 0xf2, 0x4a, 0xac, 0xdd, 0xf9, 0xaf, 0xee, + 0x44, 0xe7, 0x6e, 0xed, 0xfb, 0xd8, 0x89, 0x0e, + 0x96, 0x62, 0xcd, 0xa4, 0x4b, 0xa9, 0xe5, 0x45, + 0xb1, 0x29, 0x9b, 0x0f, 0xfc, 0xbd, 0x83, 0xab, + 0xa8, 0x54, 0x96, 0x44, 0x2c, 0x7f, 0xbb, 0xe7, + 0x52, 0x29, 0x08, 0xee, 0x14, 0xc5, 0xc2, 0xec, + 0x5a, 0xeb, 0x40, 0x40, 0xea, 0xd1, 0x3d, 0x15, + 0x73, 0xaa, 0x8c, 0x73, 0xfc, 0xf2, 0x2b, 0x49, + 0x0b, 0x13, 0x96, 0xd9, 0x8e, 0x4b, 0xbc, 0xe0, + 0xf4, 0xd2, 0xe0, 0x2e, 0x7a, 0xf0, 0x5d, 0x1f, + 0xd2, 0x92, 0x97, 0xe0, 0xaa, 0x59, 0xab, 0xc9, + 0x5c, 0xa6, 0x51, 0x1a, 0xe3, 0xd6, 0x06, 0xb9, + 0xae, 0xb8, 0x76, 0x36, 0x79, 0x37, 0x52, 0xf6, + 0x34, 0xaf, 0x27, 0x19, 0xe1, 0xc0, 0x2b, 0xdd, + 0x01, 0x15, 0xcd, 0xce, 0x44, 0xf6, 0x4c, 0x18, + 0x92, 0x69, 0xbe, 0x8a, 0x76, 0x23, 0x52, 0x13, + 0x3f, 0xf9, 0xe0, 0xf5, 0x06, 0x28, 0x7c, 0xc7, + 0xf3, 0x42, 0x0f, 0xdd, 0x40, 0x33, 0xf7, 0x99, + 0xe2, 0xad, 0x26, 0xd9, 0x53, 0x10, 0x72, 0x0c, + 0x4e, 0x43, 0x4c, 0x61, 0xfe, 0xd9, 0xc1, 0x16, + 0xa1, 0x93, 0xca, 0x3c, 0x75, 0x7f, 0x07, 0x7a, + 0x65, 0xb3, 0x53, 0x2a, 0x52, 0x00, 0xa0, 0x62, + 0xe0, 0xa3, 0x1f, 0xad, 0xd7, 0xbb, 0xc0, 0x83, + 0x5d, 0x54, 0x87, 0x5f, 0xc8, 0x2f, 0xc8, 0xbf, + 0x69, 0x04, 0x91, 0xc8, 0xa6, 0x1d, 0x4d, 0x46, + 0x91, 0xfc, 0x26, 0xf4, 0x16, 0xd1, 0xa4, 0xbf, + 0x5c, 0xa2, 0x6c, 0xdd, 0xb4, 0x40, 0xf2, 0x2e, + 0xa2, 0xad, 0xf7, 0xf4, 0xa5, 0x8a, 0x3e, 0x23, + 0x64, 0x08, 0xc8, 0xa1, 0xa0, 0xf0, 0x5d, 0x70, + 0xd2, 0x77, 0xfd, 0xc8, 0x50, 0x83, 0x0f, 0xd6, + 0x2b, 0xe4, 0x1f, 0x52, 0x34, 0x33, 0x68, 0xfd, + 0x92, 0xbe, 0x9f, 0x97, 0x6b, 0x8d, 0x81, 0x91, + 0x0f, 0xef, 0x65, 0xc8, 0x0d, 0x15, 0x01, 0x77, + 0x58, 0xb2, 0xf4, 0x1b, 0x06, 0x7e, 0xf5, 0xca, + 0x15, 0x2e, 0x38, 0xd8, 0x81, 0x1c, 0x1c, 0xa0, + 0xb6, 0x13, 0x6a, 0x2b, 0x71, 0x34, 0x52, 0xd7, + 0x1d, 0xbd, 0x37, 0x59, 0xbc, 0x86, 0x25, 0x2b, + 0xa8, 0x93, 0xce, 0x1a, 0x03, 0x16, 0xfe, 0x01, + 0x57, 0x99, 0x24, 0x25, 0x2c, 0xb3, 0xab, 0x1e, + 0x2d, 0x65, 0x20, 0x89, 0x17, 0x02, 0x0e, 0x0a, + 0xf5, 0x1e, 0xc7, 0xff, 0x1f, 0x61, 0xa9, 0x54, + 0x18, 0xd4, 0xba, 0x50, 0x57, 0x02, 0xa1, 0xab, + 0x22, 0x2e, 0x07, 0xea, 0xa9, 0xa3, 0x83, 0x4f, + 0x27, 0xf5, 0xc5, 0xee, 0x3c, 0x3b, 0x10, 0xad, + 0x32, 0x2b, 0x1c, 0x03, 0xcb, 0xaf, 0x98, 0x83, + 0x54, 0xc3, 0x68, 0x63, 0xd4, 0xe0, 0x0e, 0x3c, + 0x1a, 0x4e, 0xc0, 0x81, 0xd0, 0xe8, 0x6a, 0x62, + 0x6b, 0x3e, 0x6f, 0xc4, 0xc6, 0x33, 0x4e, 0x26, + 0x21, 0xf5, 0x04, 0xdf, 0xfa, 0xce, 0x45, 0xaf, + 0xdc, 0x5e, 0x1b, 0xad, 0x93, 0xca, 0xf5, 0xcf, + 0xd7, 0xee, 0x0c, 0x5c, 0x5e, 0xb4, 0xf0, 0x92, + 0xd2, 0xf2, 0xf0, 0xa9, 0x1e, 0xab, 0x80, 0x68, + 0x46, 0xef, 0xcc, 0x26, 0x0c, 0x5c, 0xdd, 0x4e, + 0x83, 0xb8, 0xb9, 0x53, 0x6e, 0xf8, 0x93, 0x38, + 0x67, 0xa4, 0x41, 0x87, 0x72, 0xe7, 0x7e, 0x86, + 0xc9, 0x49, 0x00, 0x33, 0xb1, 0x38, 0x6c, 0x71, + 0xd7, 0x1d, 0x8e, 0x61, 0x01, 0xb6, 0x57, 0xa9, + 0xf1, 0xac, 0x15, 0xc2, 0x83, 0x77, 0xca, 0x64, + 0xca, 0x7b, 0x6c, 0xa1, 0x10, 0x1b, 0x13, 0xd0, + 0xd3, 0x9e, 0x9e, 0x10, 0x70, 0xc8, 0x1a, 0xbb, + 0x3f, 0x19, 0x86, 0xab, 0x01, 0x0e, 0xea, 0x34, + 0x22, 0xea, 0xe2, 0x15, 0xb7, 0xed, 0x21, 0x21, + 0x75, 0xa5, 0xe7, 0x08, 0xa1, 0x38, 0xe0, 0x91, + 0x05, 0x60, 0xea, 0xa7, 0x50, 0x27, 0x18, 0x07, + 0x9d, 0xe0, 0x18, 0x2b, 0xd4, 0x07, 0x59, 0x00, + 0xe6, 0x45, 0x18, 0x2a, 0x30, 0x6e, 0xf3, 0xb4, + 0xd0, 0xef, 0xa6, 0x5b, 0x71, 0xa2, 0x5a, 0x3b, + 0x89, 0x4c, 0xaf, 0x3f, 0xcb, 0x9f, 0x03, 0xfb, + 0x43, 0x7c, 0x6b, 0xd3, 0x6a, 0xea, 0xce, 0x4a, + 0x5f, 0x64, 0xb5, 0x62, 0xda, 0x5d, 0x27, 0xb7, + 0xb8, 0x11, 0xca, 0x33, 0x30, 0xec, 0x70, 0xf0, + 0x1b, 0x03, 0x50, 0xff, 0x5e, 0xa6, 0x08, 0xde, + 0x37, 0x70, 0xc0, 0x81, 0x55, 0x60, 0x17, 0xa1, + 0x85, 0xae, 0x26, 0x44, 0xe4, 0x67, 0x3c, 0x91, + 0xfd, 0xc4, 0x3d, 0x97, 0x72, 0x23, 0xf3, 0x3c, + 0x8f, 0xe0, 0xe2, 0xf2, 0x09, 0x96, 0x10, 0x67, + 0xb5, 0xfe, 0xff, 0x3d, 0x4a, 0xc8, 0x62, 0x11, + 0xa5, 0x98, 0xc1, 0x2d, 0x40, 0x82, 0x88, 0x8b, + 0xe5, 0xb0, 0x75, 0xbf, 0x2f, 0xa8, 0x6a, 0x55, + 0x49, 0x2e, 0x9c, 0x29, 0xd2, 0x7c, 0xbf, 0xf3, + 0xaa, 0x3a, 0x16, 0x4a, 0xa4, 0x15, 0xf3, 0x48, + 0xde, 0x38, 0x13, 0x44, 0x26, 0x02, 0xe6, 0xe9, + 0xa8, 0x24, 0x89, 0xb5, 0x43, 0x95, 0xe4, 0x4c, + 0xc3, 0xa0, 0xdf, 0xcc, 0x42, 0xf8, 0x8d, 0xb0, + 0x3b, 0xea, 0x10, 0xb7, 0xe1, 0x40, 0x54, 0xb9, + 0xa3, 0x2d, 0xfb, 0xb4, 0x91, 0xc0, 0x3e, 0x94, + 0xf1, 0xa1, 0x3c, 0xbe, 0xef, 0xb8, 0x70, 0x55, + 0x0a, 0x26, 0x93, 0xbf, 0xe6, 0x21, 0x92, 0x32, + 0x3c, 0x39, 0x27, 0x6a, 0x23, 0x48, 0x02, 0x35, + 0x3c, 0xd4, 0xcc, 0x04, 0xc0, 0x4e, 0xa7, 0x02, + 0x63, 0x37, 0xc2, 0xb8, 0x56, 0x1d, 0x57, 0x57, + 0x42, 0x04, 0x8d, 0xee, 0xcf, 0x8b, 0xc9, 0xc3, + 0xba, 0x3b, 0x15, 0xd7, 0xaf, 0xbf, 0x9e, 0xcd, + 0x44, 0xcf, 0xf0, 0x00, 0xb7, 0x3a, 0xfc, 0xa8, + 0x12, 0xab, 0x3a, 0x62, 0x01, 0x21, 0x46, 0xe9, + 0x1e, 0x48, 0x37, 0xfc, 0x13, 0x4d, 0xf6, 0x2a, + 0x72, 0x40, 0x75, 0x38, 0x71, 0xf2, 0x17, 0x20, + 0x2c, 0xdd, 0xc0, 0x49, 0xbc, 0x63, 0x33, 0xea, + 0x06, 0x75, 0x41, 0xe7, 0x5c, 0x1f, 0xfb, 0xf9, + 0x68, 0x83, 0xc2, 0x5a, 0x4a, 0x1e, 0x61, 0x08, + 0x57, 0xf3, 0x00, 0xba, 0x77, 0x92, 0x63, 0xa5, + 0xb7, 0xfe, 0x97, 0x22, 0xda, 0x5e, 0xd3, 0xaf, + 0xbc, 0x89, 0x0d, 0x4c, 0x37, 0xa9, 0x27, 0x4a, + 0x7f, 0xdb, 0x81, 0x39, 0x11, 0x86, 0x12, 0xf9, + 0x10, 0x50, 0xe4, 0xdb, 0x72, 0xf9, 0xae, 0x10, + 0x7c, 0xed, 0x50, 0x5c, 0x61, 0xeb, 0x42, 0x1e, + 0xa4, 0xf4, 0xf0, 0xfa, 0x45, 0x4d, 0x95, 0x2b, + 0xd4, 0x67, 0x4a, 0xe3, 0x8a, 0x15, 0x55, 0x92, + 0x77, 0x64, 0x8c, 0x51, 0x38, 0xf9, 0x26, 0x3e, + 0x68, 0xe2, 0xac, 0xbb, 0x64, 0x77, 0xe2, 0x82, + 0xa4, 0x42, 0x41, 0x38, 0xa0, 0xf0, 0xc9, 0xd8, + 0x6c, 0xe0, 0xef, 0x4c, 0xda, 0xb4, 0x92, 0xef, + 0x1b, 0xe3, 0x9b, 0xc1, 0x44, 0x3c, 0xb9, 0xb7, + 0x39, 0xac, 0x5c, 0x32, 0x39, 0xb4, 0x21, 0x85, + 0x93, 0xbc, 0xf2, 0x51, 0x43, 0xb7, 0xae, 0x1e, + 0x61, 0x9c, 0x38, 0x9c, 0xaa, 0xff, 0xde, 0xfc, + 0xbf, 0x85, 0xef, 0x17, 0x34, 0x36, 0x71, 0x5f, + 0x04, 0x16, 0xa6, 0x9e, 0xfd, 0x3a, 0x03, 0xd8, + 0xbf, 0x71, 0x70, 0x20, 0x8f, 0x7c, 0xfb, 0xff, + 0x61, 0xe0, 0xe2, 0x60, 0xa7, 0xb1, 0xc0, 0xe0, + 0xd9, 0x3f, 0xdc, 0x8d, 0x4a, 0xa4, 0x52, 0x61, + 0xaf, 0x9d, 0xdf, 0x8a, 0x0d, 0x41, 0xc0, 0x25, + 0x68, 0x12, 0x7b, 0xd5, 0xc7, 0xdb, 0x68, 0x70, + 0x2d, 0x7d, 0x95, 0x12, 0x03, 0x23, 0x0c, 0xe8, + 0x14, 0x41, 0x11, 0x28, 0xec, 0x9d, 0xd3, 0x28, + 0x77, 0x7a, 0x3c, 0x93, 0x8e, 0x5c, 0x7e, 0xb3, + 0x42, 0x9a, 0x18, 0x25, 0x93, 0xc8, 0xea, 0x43, + 0x1b, 0xbe, 0xd5, 0x27, 0xf1, 0xd4, 0xe0, 0x1e, + 0xce, 0xc7, 0xc7, 0x2c, 0x25, 0x35, 0x58, 0xb8, + 0x6c, 0xf3, 0xa2, 0xad, 0xe7, 0x58, 0x49, 0x47, + 0xf7, 0xca, 0xde, 0x8b, 0x81, 0xb7, 0x75, 0xf4, + 0x95, 0xa7, 0x5c, 0xc3, 0x2c, 0x0e, 0x1c, 0x52, + 0x9a, 0xc3, 0x2a, 0x00, 0x21, 0xa7, 0x51, 0x6b, + 0xf0, 0x05, 0x87, 0x8c, 0x42, 0x1b, 0xc3, 0x2e, + 0xa3, 0x76, 0x22, 0xd5, 0x7f, 0x56, 0x10, 0xef, + 0x98, 0x85, 0x65, 0x86, 0x71, 0x87, 0xd2, 0x8c, + 0xc0, 0x47, 0x20, 0xe8, 0xb5, 0x1c, 0xe3, 0xdd, + 0x3c, 0x5c, 0x03, 0xbb, 0x0e, 0x97, 0x3b, 0xe1, + 0x56, 0x9a, 0xd5, 0x0a, 0x63, 0xd5, 0x33, 0xaf, + 0x36, 0xca, 0xcf, 0x8f, 0x00, 0x28, 0xa3, 0x45, + 0xb8, 0xcd, 0xde, 0x73, 0xd4, 0xfa, 0x2d, 0x6f, + 0xdb, 0x93, 0xaa, 0xdd, 0x7f, 0xd2, 0x22, 0x9c, + 0x96, 0x48, 0x1e, 0xa8, 0x63, 0xbe, 0xbc, 0x0d, + 0x14, 0x3c, 0x2e, 0x11, 0x1f, 0xd2, 0xf4, 0x57, + 0xb3, 0x47, 0xf8, 0xa6, 0x1b, 0xc3, 0xa7, 0x95, + 0x2d, 0xd4, 0xca, 0xb8, 0x0d, 0xfb, 0x06, 0x85, + 0xda, 0x63, 0xf0, 0x3e, 0x9d, 0x5e, 0xee, 0xce, + 0xed, 0x74, 0x1d, 0x2c, 0x97, 0x3f, 0x71, 0x95, + 0x12, 0x03, 0xc5, 0x92, 0x46, 0x84, 0x1b, 0x07, + 0xe6, 0xb4, 0x1d, 0x3a, 0xf1, 0x89, 0x90, 0x50, + 0x10, 0x29, 0x34, 0xc0, 0x90, 0xbe, 0x4a, 0xa9, + 0x0d, 0xb0, 0x7b, 0xfb, 0x35, 0xee, 0x4e, 0x34, + 0xec, 0x5a, 0x58, 0xbc, 0xb8, 0xda, 0x38, 0x88, + 0x8c, 0x74, 0x1e, 0xc9, 0xab, 0x78, 0x2e, 0x2a, + 0x17, 0x8a, 0x43, 0x3d, 0xa1, 0x2a, 0x41, 0xb5, + 0xd6, 0xe8, 0x5b, 0xc5, 0x4a, 0x1c, 0x3c, 0x9f, + 0x8d, 0x3a, 0x69, 0x88, 0xf8, 0x80, 0xd2, 0x11, + 0xfc, 0x7e, 0x80, 0x8e, 0x7f, 0x85, 0x64, 0x9c, + 0x46, 0x58, 0xc8, 0x48, 0x98, 0x4b, 0xf5, 0x73, + 0x3f, 0x49, 0xce, 0x53, 0x2c, 0xd5, 0xfc, 0x33, + 0xf1, 0x6f, 0xd8, 0xe9, 0x2e, 0x70, 0x2e, 0xdc, + 0xe5, 0x43, 0x80, 0x38, 0xf2, 0x87, 0xed, 0x85, + 0xe4, 0x3e, 0x45, 0x14, 0x20, 0xcf, 0xa0, 0x61, + 0x4f, 0xe8, 0xd7, 0x5b, 0xb3, 0x0d, 0x0e, 0x4e, + 0x4d, 0xce, 0xbe, 0xba, 0xaa, 0x90, 0x09, 0xcb, + 0x4b, 0x5d, 0x08, 0xff, 0x52, 0xd5, 0x23, 0xbc, + 0xad, 0x8d, 0xd3, 0x06, 0x4a, 0xa0, 0x51, 0x56, + 0xa7, 0xd8, 0x33, 0xab, 0xbc, 0xd0, 0xdf, 0x92, + 0x87, 0x20, 0x2d, 0x7b, 0x5e, 0xfa, 0x30, 0xa7, + 0x06, 0x06, 0xe5, 0x4f, 0x2c, 0xb5, 0x61, 0xd7, + 0x54, 0xd3, 0xdf, 0xd0, 0x0a, 0xb0, 0x06, 0xce, + 0xf6, 0x86, 0xb7, 0x8e, 0xaa, 0x7b, 0x78, 0xd5, + 0xb9, 0xeb, 0x07, 0xac, 0x5f, 0xc5, 0xd2, 0x8c, + 0x40, 0xe0, 0x7f, 0x98, 0xd4, 0xe5, 0x4b, 0xca, + 0xfb, 0x47, 0xef, 0xef, 0xb9, 0x4d, 0x6d, 0x8f, + 0x82, 0x68, 0x74, 0x84, 0xe0, 0x0a, 0x93, 0x0f, + 0xb2, 0x01, 0xa9, 0x9f, 0x68, 0x6a, 0xe8, 0xf7, + 0xfb, 0x0b, 0xde, 0x17, 0xe0, 0x30, 0x38, 0x51, + 0xbc, 0x07, 0xb8, 0x2c, 0x91, 0x0f, 0xc1, 0x0e, + 0xa6, 0xf9, 0xf0, 0xd5, 0x48, 0x76, 0x8a, 0xde, + 0x74, 0xe3, 0x30, 0x65, 0x56, 0xb3, 0x5c, 0xe2, + 0x89, 0x8d, 0xda, 0x80, 0xad, 0x0f, 0x22, 0xfb, + 0x24, 0x1d, 0x16, 0xdd, 0x34, 0x4b, 0x90, 0x58, + 0x4e, 0x0c, 0x13, 0x28, 0xcf, 0x1d, 0xa4, 0xaa, + 0xb7, 0xf3, 0xb1, 0x66, 0xad, 0x3b, 0xcf, 0x79, + 0x12, 0x04, 0xd7, 0x79, 0xd9, 0x5f, 0xdf, 0x89, + 0xb2, 0x5b, 0xa7, 0x9a, 0x26, 0x1e, 0x67, 0x46, + 0x7c, 0x66, 0x95, 0x67, 0xe6, 0x45, 0x8b, 0x1f, + 0x65, 0x79, 0x9f, 0x6d, 0x11, 0x81, 0x17, 0x0d, + 0x11, 0xb0, 0x5c, 0xb4, 0xc7, 0x27, 0x87, 0xab, + 0x5d, 0x0a, 0x18, 0xae, 0x4e, 0x06, 0xa3, 0x3d, + 0xc7, 0xb0, 0x22, 0xba, 0x03, 0xa4, 0x0f, 0xe5, + 0x1c, 0x72, 0x2a, 0x04, 0xce, 0x83, 0xe9, 0xf3, + 0xd7, 0xc9, 0x67, 0x6c, 0x1e, 0x6b, 0x3c, 0x9b, + 0x0b, 0x5e, 0x6a, 0xa6, 0x79, 0x0a, 0xf1, 0xbe, + 0xd7, 0xb4, 0x6f, 0x45, 0x1e, 0xfb, 0x78, 0x97, + 0xaf, 0x34, 0x76, 0x95, 0x52, 0xf7, 0x3d, 0x5d, + 0x07, 0x28, 0x57, 0x9c, 0x4a, 0x0f, 0xcf, 0x0b, + 0x1b, 0xc4, 0xc2, 0x72, 0xd7, 0x72, 0x38, 0x9b, + 0xea, 0xeb, 0xee, 0xae, 0x34, 0xc8, 0x01, 0xd7, + 0xa5, 0xe3, 0xce, 0x41, 0xad, 0x02, 0x60, 0x23, + 0x18, 0x36, 0xba, 0x17, 0xfa, 0xcf, 0xe4, 0xda, + 0xdc, 0xfc, 0x82, 0xdc, 0x7c, 0x11, 0xf4, 0xb8, + 0x52, 0x5d, 0xf7, 0x2f, 0xc8, 0xfe, 0x4a, 0xe6, + 0xb9, 0xaf, 0x4b, 0x17, 0x18, 0x91, 0xc2, 0xfe, + 0xd7, 0x3a, 0x77, 0x0c, 0xa0, 0x43, 0x9c, 0x6f, + 0x13, 0x06, 0xbe, 0x6e, 0xe0, 0x1a, 0x3c, 0xf3, + 0xf5, 0xcc, 0x78, 0xfb, 0x5d, 0xd5, 0xda, 0xb7, + 0x58, 0xea, 0x86, 0x42, 0x6b, 0x32, 0xff, 0xb2, + 0xe2, 0xee, 0x03, 0x1f, 0xf4, 0xef, 0xdb, 0x53, + 0x79, 0xd5, 0x4e, 0xaf, 0x60, 0x8e, 0x02, 0xc2, + 0xcc, 0x39, 0x97, 0x7b, 0xfd, 0xa1, 0xf8, 0x7a, + 0x26, 0xe8, 0x55, 0xd6, 0xa4, 0x8b, 0xa0, 0x1b, + 0x2d, 0x63, 0xaa, 0x73, 0x71, 0x6e, 0xbf, 0x8b, + 0x3b, 0xe3, 0x1b, 0x0d, 0xbb, 0x2e, 0x44, 0x09, + 0x64, 0xac, 0xc7, 0x9e, 0xb5, 0xc6, 0x77, 0xb0, + 0x79, 0xb3, 0xaa, 0xfc, 0x67, 0x57, 0x9a, 0x50, + 0x81, 0x37, 0x14, 0x7c, 0xd7, 0xa0, 0xd4, 0x6a, + 0x79, 0x84, 0x51, 0x0e, 0x95, 0x0a, 0x30, 0xa3, + 0x60, 0x55, 0x48, 0x05, 0x16, 0xae, 0x43, 0x90, + 0xdc, 0x8e, 0x09, 0xbe, 0x79, 0xf6, 0x90, 0x74, + 0xf8, 0x20, 0x96, 0x4d, 0xa7, 0xf5, 0x1a, 0x2b, + 0xc7, 0x15, 0x9d, 0x18, 0xf7, 0x94, 0x87, 0xf7, + 0xf4, 0xfb, 0x0d, 0x61, 0xb6, 0xd7, 0xbe, 0x10, + 0x8e, 0x47, 0x3c, 0x10, 0x44, 0x90, 0x52, 0x21, + 0x83, 0xc0, 0xf5, 0x99, 0xaa, 0xbc, 0xf6, 0x55, + 0xae, 0xf5, 0xb2, 0xa4, 0xcd, 0x4d, 0xb9, 0x38, + 0x6c, 0xbc, 0x80, 0xc3, 0xad, 0xf4, 0x46, 0x31, + 0x01, 0x58, 0x2d, 0x88, 0x57, 0xc3, 0x23, 0xd1, + 0x64, 0xc9, 0xa3, 0x21, 0x6b, 0x8b, 0x8a, 0x23, + 0x2c, 0x4f, 0xa9, 0xcd, 0x67, 0xfa, 0x77, 0xad, + 0xa3, 0x16, 0xa2, 0xe5, 0x19, 0x14, 0x70, 0x41, + 0x5b, 0xda, 0x14, 0xde, 0xe3, 0xe5, 0xc1, 0x15, + 0xb4, 0x77, 0xa4, 0x9b, 0xb8, 0xb1, 0x28, 0x51, + 0x30, 0xb4, 0xf1, 0xf3, 0xf8, 0x6d, 0xd0, 0xc3, + 0x8c, 0x4c, 0x76, 0xb0, 0x9a, 0xdf, 0xc8, 0xbe, + 0xf8, 0x4a, 0x61, 0x6e, 0x3e, 0xd6, 0x3c, 0xe8, + 0xde, 0x56, 0xa0, 0x9c, 0x25, 0xbe, 0xce, 0x93, + 0x1f, 0x88, 0xfb, 0x9a, 0x1a, 0xe2, 0xff, 0x88, + 0xad, 0x10, 0xcb, 0x6c, 0xd6, 0xe7, 0x39, 0x0b, + 0xe5, 0x1a, 0x06, 0x05, 0x64, 0x5b, 0x0a, 0xdf, + 0x22, 0x58, 0xd7, 0xfb, 0x88, 0x12, 0xdd, 0xb7, + 0x52, 0x3a, 0xc9, 0xbf, 0x49, 0xdf, 0x8c, 0x87, + 0x9f, 0x84, 0xb5, 0x0a, 0xf6, 0x00, 0x52, 0xae, + 0x67, 0x12, 0x1a, 0x8c, 0x71, 0x15, 0xf5, 0xa1, + 0x13, 0x39, 0xf0, 0x91, 0x7e, 0x88, 0x7c, 0xb3, + 0x95, 0x50, 0x02, 0xa6, 0x63, 0xb5, 0x64, 0xfb, + 0x90, 0x87, 0x61, 0xe2, 0x27, 0xaf, 0x11, 0x0c, + 0x73, 0x83, 0xef, 0xa9, 0x28, 0xfe, 0xc8, 0x85, + 0x1a, 0x3a, 0xde, 0xf2, 0xe5, 0x25, 0x64, 0x6d, + 0xaa, 0x41, 0x4c, 0x80, 0x2e, 0x84, 0xff, 0xc1, + 0xc0, 0x54, 0x0c, 0x29, 0x1b, 0xa3, 0x07, 0x7c, + 0x33, 0x4c, 0x10, 0xf6, 0x6f, 0x79, 0xdf, 0xd3, + 0xf0, 0x24, 0x57, 0xf1, 0x60, 0xe1, 0xf0, 0xbd, + 0xc4, 0x1f, 0xf4, 0x67, 0xd2, 0xd3, 0xcc, 0x6a, + 0x07, 0x72, 0x44, 0x16, 0x85, 0x46, 0xd0, 0x73, + 0x87, 0xa9, 0xc7, 0x2f, 0xd1, 0xf5, 0xec, 0xe3, + 0x28, 0xa3, 0x93, 0x4f, 0xd7, 0x76, 0xc1, 0x3c, + 0x0d, 0x13, 0x33, 0xcf, 0x5b, 0xbd, 0x6a, 0x52, + 0x4e, 0xee, 0xc8, 0x5e, 0xa1, 0x58, 0x4a, 0x08, + 0x81, 0xd9, 0x23, 0xcc, 0xfb, 0x1c, 0xb2, 0xd8, + 0xa3, 0xe4, 0x53, 0xfe, 0xf4, 0x4b, 0x48, 0xc1, + 0x20, 0xa4, 0x97, 0xf8, 0x38, 0xa3, 0x69, 0xc1, + 0x11, 0xf0, 0xa1, 0x3b, 0xa9, 0x9a, 0x12, 0x61, + 0xe8, 0x8d, 0x99, 0x44, 0x3f, 0x94, 0x72, 0x82, + 0x19, 0x96, 0x62, 0xb0, 0xa6, 0x64, 0x05, 0x19, + 0x8f, 0xd6, 0x5d, 0x05, 0xbf, 0x79, 0x9e, 0x9d, + 0xe4, 0x93, 0x4c, 0xad, 0x61, 0x8c, 0x18, 0xda, + 0xb6, 0x2e, 0xb3, 0xca, 0x14, 0x4d, 0x53, 0xa4, + 0x97, 0x27, 0x10, 0x56, 0xa2, 0x67, 0x5a, 0x5a, + 0x5e, 0x13, 0xc0, 0xdb, 0xa7, 0x9f, 0x45, 0x5b, + 0xeb, 0x1a, 0x14, 0x0c, 0x8c, 0x38, 0x5e, 0x77, + 0x9a, 0xec, 0x75, 0x68, 0x93, 0x65, 0x02, 0x9c, + 0xfb, 0x62, 0x60, 0x49, 0xdd, 0xb2, 0x2a, 0x67, + 0x86, 0xe3, 0x8a, 0x7d, 0x8c, 0x46, 0x78, 0x81, + 0x60, 0x69, 0xf2, 0x3f, 0x74, 0x11, 0x35, 0xff, + 0x77, 0xa3, 0x66, 0x20, 0xfc, 0x98, 0x4a, 0x35, + 0x7a, 0x52, 0xe4, 0x90, 0x13, 0x80, 0xb9, 0xa6, + 0x73, 0x7a, 0x7d, 0x66, 0x6e, 0x6b, 0xb6, 0x43, + 0x10, 0xd5, 0x91, 0x2b, 0x66, 0xdd, 0x89, 0x87, + 0xe3, 0x8c, 0x58, 0x53, 0x2f, 0x40, 0x74, 0x45, + 0x1b, 0x77, 0x7a, 0xa4, 0x44, 0x19, 0x78, 0xba, + 0x87, 0x10, 0x41, 0x31, 0x32, 0x5f, 0x87, 0x68, + 0xde, 0x43, 0x4a, 0xef, 0x33, 0xb3, 0x11, 0x83, + 0xa9, 0xc2, 0x6f, 0x8d, 0x34, 0xe2, 0x95, 0x84, + 0x3a, 0x4f, 0x6f, 0x8c, 0x31, 0x1d, 0xb6, 0xf5, + 0x95, 0x0d, 0x01, 0x11, 0x20, 0xdf, 0x72, 0xf3, + 0x3f, 0x9a, 0x33, 0xaa, 0xb1, 0x06, 0x6a, 0x63, + 0x47, 0x91, 0x01, 0xdf, 0xb3, 0x54, 0x36, 0xfd, + 0x06, 0x2d, 0xb8, 0x08, 0xe3, 0xd3, 0x65, 0xac, + 0x66, 0x03, 0xee, 0xa4, 0x63, 0xbd, 0xd4, 0xce, + 0xbd, 0x79, 0xa7, 0x48, 0x38, 0xc5, 0x7d, 0xb5, + 0x71, 0x9a, 0x3c, 0x11, 0x7c, 0x6c, 0xe2, 0x54, + 0x02, 0x5d, 0x42, 0xab, 0x25, 0x93, 0x66, 0x01, + 0x37, 0x78, 0x35, 0x4a, 0x8c, 0x19, 0x4d, 0x00, + 0x75, 0x4f, 0xcc, 0xc0, 0x26, 0x82, 0xc1, 0x35, + 0x8c, 0xc7, 0xc2, 0x59, 0x01, 0x3e, 0x98, 0x22, + 0x88, 0x9c, 0x90, 0x75, 0x05, 0x33, 0x07, 0xb9, + 0x39, 0x81, 0x38, 0x58, 0x10, 0x29, 0xcf, 0xc8, + 0x98, 0xb2, 0x03, 0xd7, 0x5b, 0xb3, 0x18, 0xba, + 0x34, 0x0c, 0x9f, 0xab, 0xd7, 0xed, 0x29, 0x82, + 0x41, 0xe0, 0x20, 0x97, 0x57, 0x92, 0xb2, 0xb8, + 0x10, 0x2d, 0x0b, 0xa2, 0xc5, 0x8f, 0x90, 0x6f, + 0xed, 0x12, 0x56, 0x25, 0xbe, 0xfd, 0x75, 0xf7, + 0xb6, 0xf8, 0x40, 0x67, 0x39, 0x11, 0xfa, 0x15, + 0xae, 0x6a, 0x54, 0x5f, 0x32, 0x2b, 0xf8, 0x48, + 0x55, 0xbe, 0x86, 0x2f, 0x69, 0x48, 0x5b, 0x5d, + 0x4d, 0xb7, 0x35, 0xaa, 0xb6, 0x91, 0x88, 0x19, + 0x96, 0x1c, 0x68, 0xf6, 0x85, 0x9e, 0xb3, 0xb2, + 0xa3, 0x32, 0xd4, 0x52, 0x70, 0xb7, 0x62, 0xe3, + 0x14, 0xb6, 0x78, 0x5f, 0x1b, 0x1d, 0x04, 0x9c, + 0x26, 0x0c, 0x33, 0x94, 0xb1, 0x97, 0x08, 0xdb, + 0x0b, 0x39, 0x29, 0xd4, 0xbc, 0x6d, 0xdf, 0x02, + 0xc6, 0x99, 0xab, 0x99, 0x32, 0xe5, 0xce, 0x51, + 0x4f, 0xae, 0xb8, 0x8b, 0xe0, 0xaf, 0x07, 0xc4, + 0xf9, 0x41, 0x7c, 0x59, 0xa0, 0xac, 0x74, 0x4d, + 0x7e, 0x43, 0x77, 0x9c, 0x06, 0x49, 0x79, 0x8a, + 0x14, 0x73, 0x93, 0xa8, 0x5b, 0x1b, 0x34, 0x29, + 0x78, 0x04, 0x2f, 0xd7, 0x1f, 0x13, 0x90, 0xe0, + 0xdd, 0x3b, 0x42, 0x6b, 0x79, 0x6e, 0x52, 0xc7, + 0x0f, 0x38, 0xda, 0x01, 0x2c, 0x8d, 0xe6, 0x94, + 0x5d, 0x59, 0x27, 0x1d, 0x10, 0x4e, 0x11, 0x36, + 0xfb, 0x53, 0x16, 0x05, 0x25, 0xf2, 0x64, 0xd8, + 0xf9, 0xcd, 0x5c, 0xfe, 0xb4, 0x18, 0x44, 0x80, + 0x10, 0xbc, 0x3d, 0xf3, 0x1d, 0x5a, 0xf0, 0xc1, + 0xc3, 0x55, 0xff, 0x41, 0x3e, 0xe3, 0xef, 0x44, + 0xb2, 0xc0, 0x01, 0x18, 0xa2, 0x49, 0x88, 0x78, + 0x0d, 0x4c, 0xc8, 0x73, 0xcf, 0x30, 0x85, 0x3a, + 0x88, 0x90, 0x01, 0xcf, 0x69, 0x53, 0xa3, 0x18, + 0x3f, 0xd6, 0xe7, 0x94, 0x14, 0xa7, 0xae, 0xcd, + 0x6f, 0x11, 0x72, 0xfe, 0x2b, 0xb0, 0x81, 0x53, + 0xea, 0x67, 0xd6, 0xe4, 0xca, 0x42, 0xa0, 0xf9, + 0xb1, 0xd4, 0xb5, 0x3b, 0xc9, 0xf0, 0x36, 0xc1, + 0x1c, 0xf4, 0xb1, 0xf6, 0x84, 0xd0, 0x86, 0x6c, + 0x76, 0x9a, 0x03, 0xc2, 0xb6, 0x2e, 0x9a, 0x46, + 0xf5, 0x5f, 0x2c, 0x38, 0xac, 0xad, 0x6f, 0x2e, + 0x7a, 0x18, 0x2d, 0x22, 0x95, 0x5e, 0x5e, 0xc9, + 0x7a, 0x0a, 0x56, 0xe1, 0xc7, 0x15, 0xfd, 0xbf, + 0xff, 0xf7, 0x7e, 0x85, 0x20, 0xa9, 0x8a, 0x9c, + 0xa9, 0x7d, 0xe8, 0xed, 0xfc, 0x7f, 0xbb, 0xf0, + 0x05, 0x3f, 0xce, 0x4f, 0x4c, 0xee, 0xa4, 0xa0, + 0xcc, 0x9c, 0x62, 0x1e, 0xd6, 0xd0, 0x30, 0x37, + 0xb8, 0x98, 0x56, 0x1d, 0xaa, 0xd6, 0x5e, 0x73, + 0x12, 0xe4, 0x88, 0x82, 0x48, 0x64, 0x06, 0xd7, + 0x2a, 0x31, 0x50, 0x7b, 0x10, 0x17, 0xb8, 0x4c, + 0x5a, 0x8d, 0xf1, 0xfc, 0xf1, 0x33, 0x3b, 0x98, + 0x42, 0x18, 0x5b, 0x35, 0x78, 0xca, 0x8e, 0x41, + 0x52, 0xae, 0x6d, 0xe1, 0xa2, 0x9d, 0x5b, 0xbd, + 0xf3, 0x5f, 0x49, 0xc1, 0x27, 0x06, 0xc1, 0xaf, + 0xc0, 0xa3, 0x9d, 0xf3, 0x1c, 0x8e, 0x90, 0x8a, + 0xb0, 0x69, 0xb0, 0xc5, 0x11, 0x0c, 0x91, 0x14, + 0x1f, 0x5e, 0x10, 0xe1, 0x1d, 0x14, 0x30, 0x54, + 0x1e, 0x17, 0x3d, 0x31, 0x7b, 0xbf, 0x2f, 0x9d, + 0x6d, 0x63, 0x32, 0xf0, 0x9d, 0x9f, 0x95, 0x3d, + 0x0b, 0xd2, 0x4d, 0x10, 0xe2, 0x3f, 0x67, 0x69, + 0x43, 0x9a, 0x4a, 0x2c, 0x54, 0x71, 0xa8, 0xa0, + 0x9e, 0x9f, 0x10, 0xaf, 0x1b, 0xce, 0x99, 0xe3, + 0x25, 0x32, 0x10, 0x54, 0x80, 0xfe, 0xda, 0x57, + 0xd0, 0xb2, 0x92, 0x7f, 0xbb, 0x5f, 0xe7, 0x4d, + 0x1b, 0x3d, 0x46, 0x4d, 0xe4, 0x4c, 0xd6, 0xaf, + 0x1a, 0x32, 0x12, 0x40, 0xb8, 0x84, 0x8e, 0xe4, + 0x80, 0xce, 0x7e, 0xc1, 0x13, 0x8b, 0xb0, 0xb7, + 0x6f, 0x24, 0xba, 0x85, 0x50, 0x83, 0xc3, 0xcf, + 0x19, 0xb3, 0xf0, 0xc7, 0xee, 0x68, 0xbe, 0x9e, + 0x6d, 0xb9, 0xfb, 0xd5, 0x29, 0xce, 0x82, 0xcd, + 0x69, 0x16, 0x68, 0x6b, 0x6a, 0xf4, 0x02, 0x32, + 0xce, 0x60, 0x37, 0x0c, 0xb9, 0x38, 0x92, 0x9c, + 0x42, 0xa9, 0x0b, 0x53, 0x96, 0xfe, 0x39, 0xc1, + 0x24, 0x65, 0x9b, 0xcd, 0xe7, 0x8d, 0x36, 0x07, + 0x9f, 0x1d, 0x35, 0x8e, 0xdc, 0x4c, 0xb5, 0x68, + 0xc5, 0xfd, 0x44, 0x19, 0xf2, 0x6c, 0x59, 0x1c, + 0xb1, 0x0b, 0x35, 0x48, 0x86, 0x1a, 0x05, 0x22, + 0x03, 0x0c, 0x0c, 0xa2, 0x92, 0x90, 0x35, 0xfb, + 0x37, 0x94, 0xc7, 0x15, 0x84, 0xae, 0xe8, 0x05, + 0xa0, 0xf7, 0x30, 0x11, 0x5c, 0xe4, 0x5d, 0x3e, + 0x12, 0x54, 0x80, 0x54, 0x6b, 0x09, 0x8c, 0xce, + 0x80, 0x5e, 0xa7, 0xc8, 0x6a, 0x0c, 0x56, 0xe1, + 0x18, 0x7d, 0xc9, 0x39, 0xc1, 0xef, 0xe3, 0x25, + 0xa0, 0x8b, 0x2f, 0x60, 0x3a, 0x43, 0x39, 0xa6, + 0x28, 0x28, 0x7b, 0x4c, 0x77, 0xd4, 0x49, 0x61, + 0x46, 0xe9, 0x1b, 0x45, 0xd6, 0xb1, 0x56, 0xe1, + 0x7d, 0x34, 0xcd, 0x06, 0xb6, 0x67, 0x8d, 0x7d, + 0x7a, 0xe2, 0xbe, 0x68, 0x35, 0xa6, 0x78, 0xe5, + 0x47, 0x48, 0xb7, 0xc7, 0xde, 0xcd, 0xc9, 0x05, + 0xb4, 0xe7, 0x50, 0x48, 0xe1, 0x4b, 0xfe, 0x76, + 0x77, 0xc6, 0xf7, 0x5f, 0xcb, 0xc2, 0xa8, 0xd7, + 0xd6, 0x8a, 0xe5, 0x49, 0xd9, 0xca, 0x45, 0xf4, + 0xda, 0xcd, 0x33, 0xd1, 0x59, 0x2d, 0x9e, 0xc1, + 0x5c, 0xe6, 0x01, 0x18, 0xb8, 0xf0, 0x5e, 0xb1, + 0x69, 0x95, 0x2f, 0x02, 0x2a, 0xe7, 0x4a, 0xd7, + 0xd1, 0xc3, 0xd5, 0x6f, 0x15, 0xc8, 0xdc, 0x29, + 0xde, 0xb9, 0x3f, 0x8b, 0xa6, 0xbc, 0xdd, 0x25, + 0x84, 0x35, 0x3c, 0x90, 0x2d, 0xc2, 0x1e, 0x98, + 0x8a, 0x50, 0x09, 0x77, 0x42, 0xe9, 0x35, 0x8a, + 0x7c, 0x97, 0xbf, 0xe8, 0xbf, 0x56, 0xd0, 0x8b, + 0x65, 0xd3, 0xaf, 0x1e, 0x05, 0x94, 0xfa, 0xac, + 0xa8, 0x2b, 0x28, 0xcb, 0x37, 0x3e, 0xe8, 0xbb, + 0x66, 0x3a, 0xed, 0xb2, 0x48, 0x10, 0x0f, 0x3a, + 0x5a, 0xc5, 0xdb, 0x26, 0x0e, 0xaa, 0x5e, 0x69, + 0x15, 0xd6, 0x81, 0xae, 0xbd, 0xe6, 0x03, 0xf1, + 0xf6, 0x37, 0xc8, 0xde, 0x70, 0x1f, 0x64, 0xb9, + 0x5e, 0xbf, 0x2e, 0x4f, 0xb1, 0xea, 0xa0, 0x17, + 0xe6, 0x7c, 0xf9, 0x2f, 0x1e, 0xd8, 0x58, 0xde, + 0xa7, 0xf0, 0x46, 0x52, 0x95, 0xdf, 0xa4, 0x96, + 0xd0, 0xc4, 0x97, 0x2b, 0x95, 0xcd, 0x5e, 0x40, + 0x23, 0x5c, 0x10, 0xee, 0xba, 0x72, 0x9b, 0xcf, + 0x0b, 0xe8, 0x18, 0x3a, 0x70, 0xd2, 0x5e, 0x07, + 0x68, 0x93, 0xef, 0x4a, 0x5b, 0x8d, 0x72, 0x41, + 0x4e, 0xea, 0x33, 0x6a, 0x0a, 0x5e, 0xfb, 0x02, + 0x3f, 0xd4, 0xed, 0x5b, 0xe0, 0x42, 0x84, 0xd4, + 0xaa, 0x85, 0xdc, 0x5b, 0x67, 0xee, 0x71, 0x67, + 0xba, 0x8e, 0xd2, 0xbe, 0x61, 0xdf, 0x5a, 0x26, + 0xb9, 0xf0, 0x77, 0x81, 0x53, 0x24, 0x16, 0xcb, + 0x8c, 0xb8, 0x06, 0x6e, 0x68, 0xda, 0xc8, 0x2d, + 0x17, 0x54, 0xdb, 0x46, 0xcb, 0xfd, 0x1f, 0x3d, + 0x94, 0x81, 0x09, 0x4b, 0xfa, 0xb1, 0x46, 0xd9, + 0x11, 0xa3, 0xb7, 0x31, 0x9c, 0xd2, 0x38, 0xd6, + 0xba, 0x3d, 0xa3, 0x74, 0xd8, 0xf1, 0x24, 0xe8, + 0x9c, 0xcb, 0x1d, 0xf9, 0x4a, 0xf7, 0xc8, 0x4b, + 0xfe, 0x97, 0x7c, 0xa1, 0x02, 0xeb, 0x40, 0xc3, + 0x89, 0x71, 0x01, 0xcd, 0x33, 0x2a, 0xc2, 0x82, + 0xce, 0x62, 0x8d, 0x53, 0x7c, 0xdf, 0xce, 0xd7, + 0xf5, 0xa8, 0x4f, 0xf2, 0xf2, 0x2e, 0xc1, 0xeb, + 0x97, 0x99, 0x37, 0x3c, 0x53, 0xa6, 0xb4, 0x46, + 0x05, 0x64, 0x92, 0x87, 0x08, 0x3c, 0x23, 0x4b, + 0x9d, 0x67, 0x18, 0xf9, 0xe2, 0x0b, 0x1c, 0x39, + 0xd3, 0x87, 0x70, 0xc0, 0xb9, 0x1e, 0x52, 0x0a, + 0x0f, 0x48, 0xe2, 0xe7, 0x51, 0x72, 0x94, 0xf7, + 0xa3, 0xdc, 0xe5, 0x66, 0x33, 0x39, 0x54, 0x06, + 0x55, 0x93, 0x30, 0xf9, 0x5e, 0x76, 0x8f, 0xe0, + 0x59, 0x4d, 0x0d, 0xa7, 0xf5, 0xbe, 0xdb, 0x20, + 0xad, 0x0d, 0x76, 0x88, 0x5f, 0x9c, 0x7c, 0x75, + 0x2f, 0x2a, 0x0b, 0x79, 0x6e, 0xd3, 0xe2, 0x66, + 0xf5, 0x4a, 0x2d, 0x87, 0x87, 0x49, 0x84, 0x17, + 0xa2, 0x62, 0x4c, 0xbb, 0xe4, 0x6e, 0x98, 0x10, + 0xc9, 0xfb, 0x8a, 0x04, 0x68, 0x8d, 0x22, 0x66, + 0xad, 0xea, 0x2a, 0xc9, 0x97, 0x2d, 0x3c, 0xbc, + 0xd0, 0x77, 0x5f, 0xe6, 0xb8, 0x7f, 0xe6, 0xf6, + 0x39, 0xbf, 0x56, 0x0e, 0x26, 0x6d, 0xc5, 0x3e, + 0x53, 0x19, 0xd6, 0xb4, 0x57, 0x36, 0xa3, 0xc6, + 0xd3, 0x3d, 0x66, 0x79, 0x30, 0x5c, 0x14, 0x0c, + 0x0f, 0x3e, 0x96, 0xae, 0x90, 0x97, 0xab, 0x0d, + 0x9f, 0xc3, 0xe7, 0x66, 0x3e, 0xe0, 0x31, 0x43, + 0x4b, 0x01, 0xb3, 0x0e, 0x9e, 0x8c, 0x82, 0x4a, + 0x8c, 0xc7, 0x79, 0x85, 0xdf, 0x75, 0x0d, 0xb4, + 0x2b, 0x03, 0x14, 0xef, 0x72, 0x58, 0xfd, 0x64, + 0xc8, 0xe3, 0x0d, 0x9a, 0x14, 0x6f, 0x76, 0xf9, + 0x46, 0xd1, 0xd2, 0x81, 0xb3, 0x16, 0x6e, 0xc7, + 0x76, 0x82, 0xce, 0xf4, 0xee, 0x33, 0x00, 0xe6, + 0x77, 0xc4, 0xad, 0x4f, 0x06, 0xa7, 0x48, 0x80, + 0x9e, 0x21, 0x66, 0xca, 0x75, 0x69, 0x57, 0xcb, + 0xf0, 0x67, 0x6a, 0xaa, 0x8f, 0x88, 0x14, 0xbd, + 0x65, 0x62, 0xe2, 0xad, 0xcc, 0x22, 0x88, 0x7b, + 0x94, 0xbd, 0x0e, 0xcd, 0xb6, 0x69, 0xa2, 0xcb, + 0x7d, 0x57, 0x5c, 0xb4, 0x92, 0x80, 0x13, 0x99, + 0x84, 0xf3, 0x79, 0x0a, 0x2d, 0x70, 0xa4, 0xe0, + 0xde, 0xc6, 0x32, 0xb0, 0x8a, 0x62, 0xb5, 0xcf, + 0xfa, 0x5e, 0x5a, 0x92, 0x32, 0x7d, 0x34, 0x07, + 0xb5, 0x52, 0x3a, 0xb5, 0x7d, 0x0f, 0xa1, 0xba, + 0x56, 0xd0, 0x07, 0x76, 0x11, 0xf2, 0xc3, 0x33, + 0x9d, 0xbd, 0x12, 0x35, 0x5e, 0xf7, 0x05, 0x88, + 0x76, 0x94, 0xa6, 0xbf, 0xed, 0xb8, 0xa4, 0xa2, + 0x0c, 0xbe, 0x0f, 0x6a, 0xaf, 0xf3, 0x1b, 0x33, + 0x4a, 0xb7, 0x68, 0x3f, 0xbe, 0x95, 0x13, 0x97, + 0x0f, 0x15, 0x17, 0x1b, 0x23, 0xaa, 0x08, 0x78, + 0xa6, 0x5b, 0x08, 0xa2, 0x9d, 0x03, 0xa8, 0xa7, + 0x39, 0xdc, 0xbc, 0x9a, 0x85, 0xf5, 0xe5, 0x55, + 0x59, 0x3c, 0xef, 0xf9, 0x3f, 0x22, 0x8e, 0xf8, + 0xd8, 0x3e, 0x02, 0x0b, 0xd8, 0x78, 0x4b, 0x15, + 0x7f, 0xaa, 0x2c, 0xff, 0xbe, 0x77, 0x33, 0xc7, + 0x6a, 0x12, 0xaa, 0xa4, 0xbe, 0xc0, 0x3b, 0xcb, + 0x13, 0x9d, 0x9c, 0x5a, 0x9f, 0x8a, 0x57, 0x36, + 0x4f, 0x02, 0x5a, 0xf8, 0x1d, 0x97, 0x77, 0x43, + 0xc8, 0xa5, 0xb7, 0x9b, 0x10, 0x98, 0xfd, 0x58, + 0xbf, 0x42, 0xf6, 0xbf, 0xff, 0x6c, 0x40, 0x18, + 0x18, 0xdf, 0xac, 0x57, 0x71, 0xea, 0xcc, 0x8e, + 0xfd, 0xfe, 0x10, 0xfb, 0xb9, 0xfe, 0xbc, 0x9a, + 0x9c, 0x27, 0xe4, 0x10, 0x15, 0x94, 0x41, 0xa1, + 0xcc, 0xf6, 0x25, 0x49, 0x4f, 0x96, 0xc1, 0x8c, + 0x9e, 0x3e, 0x18, 0x29, 0x49, 0x92, 0xe7, 0xfe, + 0x22, 0xff, 0xed, 0x02, 0x16, 0x90, 0xef, 0xac, + 0xec, 0x95, 0x1d, 0x5b, 0x94, 0x9c, 0xf6, 0x7c, + 0x1b, 0x5a, 0x9d, 0xb0, 0x9b, 0x05, 0x36, 0xbf, + 0xef, 0xec, 0x63, 0x35, 0x40, 0x24, 0x45, 0x40, + 0x30, 0x1a, 0x9b, 0x90, 0xc3, 0xc2, 0xf7, 0x37, + 0xfb, 0x08, 0x8e, 0x48, 0x19, 0x48, 0xed, 0xa8, + 0xa8, 0x04, 0x6f, 0xd0, 0x33, 0xe9, 0xb8, 0x8d, + 0xe7, 0x1e, 0x5c, 0x47, 0x74, 0xc0, 0x66, 0x30, + 0x4e, 0xa7, 0x86, 0x73, 0xf1, 0xe5, 0x78, 0xa6, + 0xe0, 0xc1, 0xda, 0x13, 0x72, 0x07, 0x85, 0x34, + 0x63, 0x95, 0x49, 0x30, 0x4b, 0x9d, 0x03, 0xf1, + 0x7a, 0x6b, 0x91, 0xa2, 0x85, 0x41, 0xf9, 0x4a, + 0xd6, 0xff, 0xff, 0x86, 0xf7, 0xf0, 0xce, 0xb9, + 0x07, 0xf1, 0x88, 0x04, 0x33, 0xaa, 0xeb, 0x54, + 0xb2, 0x1c, 0x8e, 0x2e, 0x7b, 0x04, 0xa8, 0xcc, + 0x2c, 0x7a, 0xb3, 0xad, 0x1a, 0x89, 0x38, 0x89, + 0xd7, 0x11, 0x3a, 0x8c, 0xcf, 0xe3, 0xc5, 0xba, + 0xb0, 0xcc, 0xc4, 0xe3, 0x33, 0xf3, 0x18, 0xba, + 0xec, 0x56, 0xd9, 0x1c, 0x40, 0x70, 0x0d, 0x4e, + 0x97, 0x01, 0x23, 0xf3, 0x5a, 0xdc, 0xbf, 0x68, + 0x93, 0xc2, 0x1d, 0x8a, 0x96, 0xb7, 0xac, 0x18, + 0x6f, 0xf7, 0x84, 0x71, 0x0d, 0x3d, 0xf8, 0xba, + 0xdf, 0xb6, 0x89, 0x1d, 0x78, 0x19, 0xf2, 0x59, + 0xe9, 0x15, 0x55, 0x29, 0x73, 0x50, 0x59, 0x14, + 0x02, 0x21, 0x16, 0x8f, 0x0f, 0xdf, 0xa5, 0xf0, +}; + +static struct crc_test { + uint32_t crc; /* random starting crc */ + uint32_t start; /* random offset in buf */ + uint32_t length; /* random length of test */ + uint32_t crc32c_le; /* expected crc32c_le result */ + uint32_t crc32_be; /* expected crc32_be result */ +} test[] = { + {0xffffffff, 0x00000000, 0x00001000, 0x13934bef, 0xd8ddcdc3}, + {0xfe7328ea, 0x00000763, 0x00000717, 0xed2c0d70, 0xc863aef8}, + {0x4c40684e, 0x00000721, 0x0000011e, 0xd7f46ccc, 0x173a11c4}, + {0x6b487f90, 0x00000264, 0x000007bc, 0x759e9939, 0xd6307c56}, + {0x9f5810db, 0x00000afa, 0x00000255, 0x2685197f, 0x2e5c9201}, + {0xb15c4755, 0x00000d5b, 0x000002a4, 0xd8fadcb5, 0xf682c4be}, + {0x06518253, 0x00000ffb, 0x00000004, 0xabee2433, 0x3d8abdf9}, + {0xd9e71c55, 0x00000a2a, 0x00000259, 0x96682af2, 0x47b4d26c}, + {0x0c1ae843, 0x00000ce4, 0x0000031b, 0x7b637c43, 0x62b47e8b}, + {0xec3cd517, 0x000002ff, 0x00000566, 0x5d719a77, 0xff5bc5b7}, + {0x77828e95, 0x0000067f, 0x0000038f, 0x43ee5b6c, 0x1a0cfacd}, + {0xec87b4e3, 0x00000d1c, 0x000002e3, 0x2ddd2eee, 0x275118a7}, + {0x412158bb, 0x00000eee, 0x00000111, 0x67b38ba2, 0xa74ecff5}, + {0x2e52de3e, 0x00000c4a, 0x000003b5, 0xbcc5d61d, 0xbd800707}, + {0x6ddaae8b, 0x00000d99, 0x00000266, 0x8b535544, 0xecbde1a1}, + {0x049b6cb1, 0x000009c5, 0x000000b0, 0xfc22cabc, 0xfb78eb9f}, + {0x77d4b954, 0x0000028a, 0x000007fa, 0x71d00923, 0x8c116f85}, + {0x5e192355, 0x00000ac1, 0x000001fa, 0xb966b81a, 0x5aa17bbe}, + {0x7d80b71d, 0x00000213, 0x000001e0, 0x2bba371a, 0xb5906aa6}, + {0x01f6f1e4, 0x000001d6, 0x00000395, 0xb7e8a647, 0x3ad112b1}, + {0x1dfabb13, 0x00000e14, 0x000001eb, 0x53917fba, 0xbaee0339}, + {0xb00a4449, 0x00000bf6, 0x00000409, 0xedecb577, 0x6f3a3979}, + {0x7ecd3981, 0x0000083f, 0x0000016b, 0xefef62b9, 0xe3e52eed}, + {0xf8f330d2, 0x000004be, 0x00000757, 0x9357c9f3, 0x0835bc1b}, + {0x03c38af2, 0x00000d23, 0x000002dc, 0x360fa8c0, 0x2ca885e6}, + {0x687bb79b, 0x00000f3d, 0x000000c2, 0x448d3be2, 0x79be2f78}, + {0x6710f550, 0x000009e9, 0x00000603, 0xdbfd1998, 0x1d25f627}, + {0x873171d1, 0x00000787, 0x000004d5, 0xab7f1b62, 0xa76a5656}, + {0x373b1314, 0x00000f0f, 0x000000f0, 0x184098ab, 0xba273974}, + {0x90fad9cd, 0x00000ead, 0x00000152, 0x23ce52ff, 0xb7bc958c}, + {0x19676fe7, 0x0000007d, 0x0000070d, 0xf8a76f1e, 0xf882b644}, + {0x89facd45, 0x000005f3, 0x00000473, 0x4331a006, 0xe9dc1396}, + {0x6f173747, 0x00000fc3, 0x0000003c, 0xb012f08e, 0xc6b888ee}, + {0x4b44a106, 0x0000075a, 0x0000008b, 0xf6f7ac38, 0x60cd2b74}, + {0xb620ad06, 0x00000774, 0x0000017e, 0xd34558e6, 0x3a0a615b}, + {0x976f21e9, 0x000008d7, 0x0000034a, 0xe533aa3a, 0xa99e60be}, + {0x687628c0, 0x000006c5, 0x0000061b, 0x3a840b15, 0x9bfcaef2}, + {0xe24ac108, 0x00000cd0, 0x0000032f, 0x51010ae8, 0x20958672}, + {0x361c44a3, 0x00000304, 0x00000719, 0xfd7bd481, 0xd70ff2b2}, + {0xd93ff95e, 0x00000db7, 0x0000008e, 0xcfbbc304, 0xad716acd}, + {0xed752d12, 0x00000883, 0x00000091, 0x65a6c868, 0x95c71c7b}, + {0xb4ff4b54, 0x000003d3, 0x000001c1, 0xf82597e7, 0x44b7f99b}, + {0x111b520f, 0x00000708, 0x000000eb, 0xc3e109f3, 0x71bc01ee}, + {0x62c806f2, 0x00000ba3, 0x0000045c, 0x874d3a72, 0xc539b753}, + {0x40d97470, 0x000005e1, 0x0000058d, 0x87a9684f, 0xea6073a5}, + {0x4312179c, 0x00000056, 0x0000070e, 0x809a00f5, 0x209aea3b}, + {0x13d5f84c, 0x00000a2d, 0x00000104, 0xf3d27578, 0xe087a8b6}, + {0x1f302cb2, 0x00000151, 0x00000014, 0x1e162693, 0x95e4b90e}, + {0xe491db24, 0x00000600, 0x000006f6, 0x7ff09615, 0x77611523}, + {0xf9a98069, 0x000002ba, 0x000002ad, 0x01af7387, 0xea925faa}, + {0xe9c477ad, 0x0000015f, 0x00000778, 0x6facf9a0, 0x1130f736}, + {0x353f32b2, 0x0000087c, 0x00000783, 0x6cc964ea, 0x32459994}, + {0x78e1b24f, 0x00000650, 0x000006a8, 0xb3bb7c27, 0x5a632f78}, + {0x61aa400e, 0x00000049, 0x00000254, 0xb8cd1681, 0xdf2652d5}, + {0xb84b10b0, 0x00000f73, 0x0000008c, 0x406a6450, 0x3619d31b}, + {0x9fa99c9c, 0x00000a7c, 0x000004d7, 0xfb3d21b4, 0xea31c743}, + {0x3fc9ebe3, 0x00000cd9, 0x000000d6, 0x43803f9c, 0x1f76a809}, + {0x529879cd, 0x000002f2, 0x00000595, 0x78b4c6a6, 0x63b9b93f}, + {0x3a933019, 0x00000516, 0x00000266, 0xdcb45436, 0x8f99c98c}, + {0x887b4977, 0x00000227, 0x0000038d, 0xc5f7c3d9, 0xaf5e3091}, + {0x770745de, 0x000008c6, 0x00000739, 0xf69145e8, 0x53d0dce1}, + {0x28be3b47, 0x00000c46, 0x0000032b, 0x764c028f, 0x106d0905}, + {0x5013a050, 0x00000cf6, 0x00000309, 0xea8fe164, 0x62180b57}, + {0x2ec4c9ba, 0x000006e8, 0x0000078d, 0xa35557a9, 0xf44430a4}, + {0xa9f950c9, 0x00000d33, 0x000002cc, 0x41ea8618, 0x587b4eb3}, + {0x5b520229, 0x000007b2, 0x00000484, 0x44569f1f, 0x92406c32}, + {0xd8dcbbfc, 0x0000002f, 0x0000048c, 0xdb88ab8b, 0x13bfe70e}, + {0x25529792, 0x00000d1d, 0x000002e2, 0x20cda404, 0x19d3b4e4}, + {0x9f3f6d71, 0x00000238, 0x0000079a, 0x0720443e, 0x3c107021}, + {0x64121215, 0x000007ff, 0x0000038f, 0x6aacff2c, 0xb82fdc3e}, + {0xfb6cdde0, 0x00000ef8, 0x00000107, 0xbd43a0f1, 0xab0d3c1d}, + {0x221c9d6f, 0x000007b6, 0x0000014f, 0xb67f834b, 0x1371ad05}, + {0x030e1de4, 0x00000836, 0x000004b4, 0x0d67d26a, 0xe2e72df1}, + {0xb56fa6cf, 0x00000c07, 0x000003f8, 0x60601ac1, 0x039de73e}, + {0xb55c89f5, 0x0000098e, 0x000001d4, 0x2400efbe, 0xfe39a2bb}, + {0x5e90b6d5, 0x0000070b, 0x000003ea, 0x3bb5d6ea, 0xf0f794a0}, + {0x2a7045ae, 0x00000961, 0x00000633, 0xfca89e4b, 0xe66ce41c}, + {0x8b374ea9, 0x000006ba, 0x00000780, 0xbce036ed, 0x4cb28ef7}, + {0x8bd90bc9, 0x00000562, 0x00000369, 0xcb26a24b, 0x40236d1d}, + {0x5b1b1762, 0x000000fd, 0x0000051a, 0x33cdda07, 0xc32e420a}, + {0xa4153555, 0x0000058f, 0x000005c7, 0xbe50eeca, 0x83a67f35}, + {0x0be1f931, 0x00000651, 0x00000672, 0x95a25753, 0x88f1aac1}, + {0xb7e78618, 0x00000a7f, 0x000002bb, 0xe06bcc1c, 0x74274f66}, + {0x4a9bc41b, 0x00000e51, 0x000001ae, 0x709e8d2c, 0x54eff534}, + {0xfc359d13, 0x00000440, 0x000002f8, 0x0a58451f, 0x55e9363f}, + {0x5aa48619, 0x000006d1, 0x00000284, 0x928ead83, 0x31041c06}, + {0xa609afa8, 0x0000053e, 0x00000272, 0xb048c141, 0x4704efba}, + {0x3f108afb, 0x00000949, 0x00000150, 0x9a6bb5bc, 0x4e4430c8}, + {0x79bec2d3, 0x000008ed, 0x00000712, 0x32692d57, 0x11d52a7b}, + {0x9429e067, 0x00000bc3, 0x0000043c, 0x5295ceff, 0x04640f4d}, + {0xae58b96a, 0x0000082d, 0x000007d2, 0xc2a681ba, 0xf7ca4a2c}, + {0x95df24be, 0x00000985, 0x000004c1, 0x3a287765, 0x2c4af003}, + {0x5e94976f, 0x00000596, 0x000004ed, 0xff00c489, 0x5ae11687}, + {0xf5e5f1de, 0x00000d31, 0x000002ce, 0x35f28e91, 0x30d47957}, + {0xa2c219cf, 0x00000a3c, 0x00000374, 0x707d21eb, 0x2a14a255}, + {0xf21b6ceb, 0x00000919, 0x00000135, 0x0847fb8b, 0xcb8d3b93}, + {0xaa988728, 0x00000787, 0x00000771, 0x885aeaa4, 0x6531b509}, + {0xaa5dfaac, 0x000003e5, 0x0000051b, 0x52c48ab7, 0xe43cc5e9}, + {0x0a053968, 0x00000d2a, 0x000002d5, 0x7a90256d, 0x8004765c}, + {0x1421dc20, 0x00000eef, 0x00000110, 0x97d6da24, 0x1378f6ff}, + {0xb47c2166, 0x00000a6a, 0x00000209, 0xcfd6cc52, 0x676e14a5}, + {0x77dd1955, 0x000000de, 0x00000266, 0xba74bcaa, 0xc71b429c}, + {0x68a03cc2, 0x0000082f, 0x000007b0, 0x752bd5d8, 0x19ed14aa}, + {0x0226b0a3, 0x00000a5f, 0x000005a0, 0x82de4970, 0xf654d3ed}, + {0x637bf3b1, 0x00000d93, 0x0000026c, 0x5c7115cb, 0x3cccb57e}, + {0x3b120edf, 0x00000c13, 0x000003ec, 0x80d7d20f, 0x92132798}, + {0xe2456780, 0x000002eb, 0x00000641, 0xc0a5d289, 0x6160c87a}, + {0x9b2e7125, 0x00000c0c, 0x000003f3, 0xcc15f57e, 0x6f00f637}, + {0x153033ef, 0x00000787, 0x000006b6, 0x3cde443b, 0xb46caa6e}, + {0x18458b3f, 0x0000066c, 0x00000561, 0x9a2bd8c6, 0xb6c29121}, + {0x4ff9d4b9, 0x00000c8f, 0x0000033a, 0xd0ee6d6d, 0xc81cf380}, + {0xdf84b5d9, 0x00000802, 0x0000029a, 0xdab0d74a, 0xb2464559}, + {0x81ee15df, 0x000003ce, 0x00000725, 0x9942e2de, 0x4ccf571b}, + {0x5c768e04, 0x00000afd, 0x00000160, 0x36110831, 0xae0b305a}, + {0xe5e18094, 0x00000b4b, 0x000000a0, 0xffa3e4a7, 0x6c8a4f09}, + {0xed7263b6, 0x00000d0d, 0x000002f2, 0xb0006a35, 0x7e04af8c}, + {0x5bfde7d7, 0x000006fb, 0x00000554, 0xa4193b76, 0xb3a91d12}, + {0x67f4a743, 0x00000b85, 0x0000047a, 0xf05c8d8f, 0xfb472fdf}, + {0xf13bdf22, 0x00000ff7, 0x00000008, 0x816351eb, 0xf347f235}, + {0x08ecc608, 0x00000d5d, 0x00000098, 0x90492772, 0x0b7f1521}, + {0x296f52ba, 0x000004f9, 0x00000788, 0x5e5a4896, 0x1cc67088}, + {0xbe4624c2, 0x00000427, 0x000004ef, 0xcd267b94, 0x550caefd}, + {0x906f7c7c, 0x00000a05, 0x0000003f, 0x03fcfc33, 0x9ed82a02}, + {0x8f7b323e, 0x00000458, 0x000004c7, 0xcd4969c8, 0x633c38a8}, + {0x88d6593d, 0x00000597, 0x000005b5, 0xf199cd3b, 0x0491452f}, + {0x978a7768, 0x00000268, 0x000001d3, 0xb28c95bd, 0x1a42fe61}, + {0x857a621e, 0x000007a7, 0x000003a8, 0xf4bf84ab, 0xcd0694c6}, + {0xb0e121ef, 0x000005be, 0x00000644, 0x28747c14, 0xf0510c72}, + {0, 0, 0, 0, 0}, +}; + +static int test_crc32c(void) +{ + struct crc_test *t = test; + int failures = 0; + + while (t->length) { + uint32_t be, le; + le = ext2fs_crc32c_le(t->crc, test_buf + t->start, t->length); + be = ext2fs_crc32_be(t->crc, test_buf + t->start, t->length); + if (le != t->crc32c_le) { + printf("Test %d LE fails, %x != %x\n", + (int) (t - test), le, t->crc32c_le); + failures++; + } + if (be != t->crc32_be) { + printf("Test %d BE fails, %x != %x\n", + (int) (t - test), be, t->crc32_be); + failures++; + } + t++; + } + + return failures; +} + +int main(int argc, char *argv[]) +{ + int ret; + + ret = test_crc32c(); + if (!ret) + printf("No failures.\n"); + + return ret; +} +#endif /* UNITTEST */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/crc32c_defs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/crc32c_defs.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,59 @@ +/* + * 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 +#define CRC32C_POLY_BE 0x1EDC6F41 + +/* How many bits at a time to use. Valid values are 1, 2, 4, 8, 32 and 64. */ +/* For less performance-sensitive, use 4 */ +#ifndef CRC_LE_BITS +# define CRC_LE_BITS 64 +#endif +#ifndef CRC_BE_BITS +# define CRC_BE_BITS 64 +#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 + + +#define ___constant_swab32(x) \ + ((uint32_t)( \ + (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24))) + + +#if (__GNUC__ >= 3) +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#else +#define likely(x) (x) +#define unlikely(x) (x) +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/crc32c_table.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/crc32c_table.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,1044 @@ +/* this file is generated - do not edit */ + +static const uint32_t crc32table_be[8][256] = {{ +tobe(0x00000000L), tobe(0x04c11db7L), tobe(0x09823b6eL), tobe(0x0d4326d9L), +tobe(0x130476dcL), tobe(0x17c56b6bL), tobe(0x1a864db2L), tobe(0x1e475005L), +tobe(0x2608edb8L), tobe(0x22c9f00fL), tobe(0x2f8ad6d6L), tobe(0x2b4bcb61L), +tobe(0x350c9b64L), tobe(0x31cd86d3L), tobe(0x3c8ea00aL), tobe(0x384fbdbdL), +tobe(0x4c11db70L), tobe(0x48d0c6c7L), tobe(0x4593e01eL), tobe(0x4152fda9L), +tobe(0x5f15adacL), tobe(0x5bd4b01bL), tobe(0x569796c2L), tobe(0x52568b75L), +tobe(0x6a1936c8L), tobe(0x6ed82b7fL), tobe(0x639b0da6L), tobe(0x675a1011L), +tobe(0x791d4014L), tobe(0x7ddc5da3L), tobe(0x709f7b7aL), tobe(0x745e66cdL), +tobe(0x9823b6e0L), tobe(0x9ce2ab57L), tobe(0x91a18d8eL), tobe(0x95609039L), +tobe(0x8b27c03cL), tobe(0x8fe6dd8bL), tobe(0x82a5fb52L), tobe(0x8664e6e5L), +tobe(0xbe2b5b58L), tobe(0xbaea46efL), tobe(0xb7a96036L), tobe(0xb3687d81L), +tobe(0xad2f2d84L), tobe(0xa9ee3033L), tobe(0xa4ad16eaL), tobe(0xa06c0b5dL), +tobe(0xd4326d90L), tobe(0xd0f37027L), tobe(0xddb056feL), tobe(0xd9714b49L), +tobe(0xc7361b4cL), tobe(0xc3f706fbL), tobe(0xceb42022L), tobe(0xca753d95L), +tobe(0xf23a8028L), tobe(0xf6fb9d9fL), tobe(0xfbb8bb46L), tobe(0xff79a6f1L), +tobe(0xe13ef6f4L), tobe(0xe5ffeb43L), tobe(0xe8bccd9aL), tobe(0xec7dd02dL), +tobe(0x34867077L), tobe(0x30476dc0L), tobe(0x3d044b19L), tobe(0x39c556aeL), +tobe(0x278206abL), tobe(0x23431b1cL), tobe(0x2e003dc5L), tobe(0x2ac12072L), +tobe(0x128e9dcfL), tobe(0x164f8078L), tobe(0x1b0ca6a1L), tobe(0x1fcdbb16L), +tobe(0x018aeb13L), tobe(0x054bf6a4L), tobe(0x0808d07dL), tobe(0x0cc9cdcaL), +tobe(0x7897ab07L), tobe(0x7c56b6b0L), tobe(0x71159069L), tobe(0x75d48ddeL), +tobe(0x6b93dddbL), tobe(0x6f52c06cL), tobe(0x6211e6b5L), tobe(0x66d0fb02L), +tobe(0x5e9f46bfL), tobe(0x5a5e5b08L), tobe(0x571d7dd1L), tobe(0x53dc6066L), +tobe(0x4d9b3063L), tobe(0x495a2dd4L), tobe(0x44190b0dL), tobe(0x40d816baL), +tobe(0xaca5c697L), tobe(0xa864db20L), tobe(0xa527fdf9L), tobe(0xa1e6e04eL), +tobe(0xbfa1b04bL), tobe(0xbb60adfcL), tobe(0xb6238b25L), tobe(0xb2e29692L), +tobe(0x8aad2b2fL), tobe(0x8e6c3698L), tobe(0x832f1041L), tobe(0x87ee0df6L), +tobe(0x99a95df3L), tobe(0x9d684044L), tobe(0x902b669dL), tobe(0x94ea7b2aL), +tobe(0xe0b41de7L), tobe(0xe4750050L), tobe(0xe9362689L), tobe(0xedf73b3eL), +tobe(0xf3b06b3bL), tobe(0xf771768cL), tobe(0xfa325055L), tobe(0xfef34de2L), +tobe(0xc6bcf05fL), tobe(0xc27dede8L), tobe(0xcf3ecb31L), tobe(0xcbffd686L), +tobe(0xd5b88683L), tobe(0xd1799b34L), tobe(0xdc3abdedL), tobe(0xd8fba05aL), +tobe(0x690ce0eeL), tobe(0x6dcdfd59L), tobe(0x608edb80L), tobe(0x644fc637L), +tobe(0x7a089632L), tobe(0x7ec98b85L), tobe(0x738aad5cL), tobe(0x774bb0ebL), +tobe(0x4f040d56L), tobe(0x4bc510e1L), tobe(0x46863638L), tobe(0x42472b8fL), +tobe(0x5c007b8aL), tobe(0x58c1663dL), tobe(0x558240e4L), tobe(0x51435d53L), +tobe(0x251d3b9eL), tobe(0x21dc2629L), tobe(0x2c9f00f0L), tobe(0x285e1d47L), +tobe(0x36194d42L), tobe(0x32d850f5L), tobe(0x3f9b762cL), tobe(0x3b5a6b9bL), +tobe(0x0315d626L), tobe(0x07d4cb91L), tobe(0x0a97ed48L), tobe(0x0e56f0ffL), +tobe(0x1011a0faL), tobe(0x14d0bd4dL), tobe(0x19939b94L), tobe(0x1d528623L), +tobe(0xf12f560eL), tobe(0xf5ee4bb9L), tobe(0xf8ad6d60L), tobe(0xfc6c70d7L), +tobe(0xe22b20d2L), tobe(0xe6ea3d65L), tobe(0xeba91bbcL), tobe(0xef68060bL), +tobe(0xd727bbb6L), tobe(0xd3e6a601L), tobe(0xdea580d8L), tobe(0xda649d6fL), +tobe(0xc423cd6aL), tobe(0xc0e2d0ddL), tobe(0xcda1f604L), tobe(0xc960ebb3L), +tobe(0xbd3e8d7eL), tobe(0xb9ff90c9L), tobe(0xb4bcb610L), tobe(0xb07daba7L), +tobe(0xae3afba2L), tobe(0xaafbe615L), tobe(0xa7b8c0ccL), tobe(0xa379dd7bL), +tobe(0x9b3660c6L), tobe(0x9ff77d71L), tobe(0x92b45ba8L), tobe(0x9675461fL), +tobe(0x8832161aL), tobe(0x8cf30badL), tobe(0x81b02d74L), tobe(0x857130c3L), +tobe(0x5d8a9099L), tobe(0x594b8d2eL), tobe(0x5408abf7L), tobe(0x50c9b640L), +tobe(0x4e8ee645L), tobe(0x4a4ffbf2L), tobe(0x470cdd2bL), tobe(0x43cdc09cL), +tobe(0x7b827d21L), tobe(0x7f436096L), tobe(0x7200464fL), tobe(0x76c15bf8L), +tobe(0x68860bfdL), tobe(0x6c47164aL), tobe(0x61043093L), tobe(0x65c52d24L), +tobe(0x119b4be9L), tobe(0x155a565eL), tobe(0x18197087L), tobe(0x1cd86d30L), +tobe(0x029f3d35L), tobe(0x065e2082L), tobe(0x0b1d065bL), tobe(0x0fdc1becL), +tobe(0x3793a651L), tobe(0x3352bbe6L), tobe(0x3e119d3fL), tobe(0x3ad08088L), +tobe(0x2497d08dL), tobe(0x2056cd3aL), tobe(0x2d15ebe3L), tobe(0x29d4f654L), +tobe(0xc5a92679L), tobe(0xc1683bceL), tobe(0xcc2b1d17L), tobe(0xc8ea00a0L), +tobe(0xd6ad50a5L), tobe(0xd26c4d12L), tobe(0xdf2f6bcbL), tobe(0xdbee767cL), +tobe(0xe3a1cbc1L), tobe(0xe760d676L), tobe(0xea23f0afL), tobe(0xeee2ed18L), +tobe(0xf0a5bd1dL), tobe(0xf464a0aaL), tobe(0xf9278673L), tobe(0xfde69bc4L), +tobe(0x89b8fd09L), tobe(0x8d79e0beL), tobe(0x803ac667L), tobe(0x84fbdbd0L), +tobe(0x9abc8bd5L), tobe(0x9e7d9662L), tobe(0x933eb0bbL), tobe(0x97ffad0cL), +tobe(0xafb010b1L), tobe(0xab710d06L), tobe(0xa6322bdfL), tobe(0xa2f33668L), +tobe(0xbcb4666dL), tobe(0xb8757bdaL), tobe(0xb5365d03L), tobe(0xb1f740b4L)}, +{ +tobe(0x00000000L), tobe(0xd219c1dcL), tobe(0xa0f29e0fL), tobe(0x72eb5fd3L), +tobe(0x452421a9L), tobe(0x973de075L), tobe(0xe5d6bfa6L), tobe(0x37cf7e7aL), +tobe(0x8a484352L), tobe(0x5851828eL), tobe(0x2abadd5dL), tobe(0xf8a31c81L), +tobe(0xcf6c62fbL), tobe(0x1d75a327L), tobe(0x6f9efcf4L), tobe(0xbd873d28L), +tobe(0x10519b13L), tobe(0xc2485acfL), tobe(0xb0a3051cL), tobe(0x62bac4c0L), +tobe(0x5575babaL), tobe(0x876c7b66L), tobe(0xf58724b5L), tobe(0x279ee569L), +tobe(0x9a19d841L), tobe(0x4800199dL), tobe(0x3aeb464eL), tobe(0xe8f28792L), +tobe(0xdf3df9e8L), tobe(0x0d243834L), tobe(0x7fcf67e7L), tobe(0xadd6a63bL), +tobe(0x20a33626L), tobe(0xf2baf7faL), tobe(0x8051a829L), tobe(0x524869f5L), +tobe(0x6587178fL), tobe(0xb79ed653L), tobe(0xc5758980L), tobe(0x176c485cL), +tobe(0xaaeb7574L), tobe(0x78f2b4a8L), tobe(0x0a19eb7bL), tobe(0xd8002aa7L), +tobe(0xefcf54ddL), tobe(0x3dd69501L), tobe(0x4f3dcad2L), tobe(0x9d240b0eL), +tobe(0x30f2ad35L), tobe(0xe2eb6ce9L), tobe(0x9000333aL), tobe(0x4219f2e6L), +tobe(0x75d68c9cL), tobe(0xa7cf4d40L), tobe(0xd5241293L), tobe(0x073dd34fL), +tobe(0xbabaee67L), tobe(0x68a32fbbL), tobe(0x1a487068L), tobe(0xc851b1b4L), +tobe(0xff9ecfceL), tobe(0x2d870e12L), tobe(0x5f6c51c1L), tobe(0x8d75901dL), +tobe(0x41466c4cL), tobe(0x935fad90L), tobe(0xe1b4f243L), tobe(0x33ad339fL), +tobe(0x04624de5L), tobe(0xd67b8c39L), tobe(0xa490d3eaL), tobe(0x76891236L), +tobe(0xcb0e2f1eL), tobe(0x1917eec2L), tobe(0x6bfcb111L), tobe(0xb9e570cdL), +tobe(0x8e2a0eb7L), tobe(0x5c33cf6bL), tobe(0x2ed890b8L), tobe(0xfcc15164L), +tobe(0x5117f75fL), tobe(0x830e3683L), tobe(0xf1e56950L), tobe(0x23fca88cL), +tobe(0x1433d6f6L), tobe(0xc62a172aL), tobe(0xb4c148f9L), tobe(0x66d88925L), +tobe(0xdb5fb40dL), tobe(0x094675d1L), tobe(0x7bad2a02L), tobe(0xa9b4ebdeL), +tobe(0x9e7b95a4L), tobe(0x4c625478L), tobe(0x3e890babL), tobe(0xec90ca77L), +tobe(0x61e55a6aL), tobe(0xb3fc9bb6L), tobe(0xc117c465L), tobe(0x130e05b9L), +tobe(0x24c17bc3L), tobe(0xf6d8ba1fL), tobe(0x8433e5ccL), tobe(0x562a2410L), +tobe(0xebad1938L), tobe(0x39b4d8e4L), tobe(0x4b5f8737L), tobe(0x994646ebL), +tobe(0xae893891L), tobe(0x7c90f94dL), tobe(0x0e7ba69eL), tobe(0xdc626742L), +tobe(0x71b4c179L), tobe(0xa3ad00a5L), tobe(0xd1465f76L), tobe(0x035f9eaaL), +tobe(0x3490e0d0L), tobe(0xe689210cL), tobe(0x94627edfL), tobe(0x467bbf03L), +tobe(0xfbfc822bL), tobe(0x29e543f7L), tobe(0x5b0e1c24L), tobe(0x8917ddf8L), +tobe(0xbed8a382L), tobe(0x6cc1625eL), tobe(0x1e2a3d8dL), tobe(0xcc33fc51L), +tobe(0x828cd898L), tobe(0x50951944L), tobe(0x227e4697L), tobe(0xf067874bL), +tobe(0xc7a8f931L), tobe(0x15b138edL), tobe(0x675a673eL), tobe(0xb543a6e2L), +tobe(0x08c49bcaL), tobe(0xdadd5a16L), tobe(0xa83605c5L), tobe(0x7a2fc419L), +tobe(0x4de0ba63L), tobe(0x9ff97bbfL), tobe(0xed12246cL), tobe(0x3f0be5b0L), +tobe(0x92dd438bL), tobe(0x40c48257L), tobe(0x322fdd84L), tobe(0xe0361c58L), +tobe(0xd7f96222L), tobe(0x05e0a3feL), tobe(0x770bfc2dL), tobe(0xa5123df1L), +tobe(0x189500d9L), tobe(0xca8cc105L), tobe(0xb8679ed6L), tobe(0x6a7e5f0aL), +tobe(0x5db12170L), tobe(0x8fa8e0acL), tobe(0xfd43bf7fL), tobe(0x2f5a7ea3L), +tobe(0xa22feebeL), tobe(0x70362f62L), tobe(0x02dd70b1L), tobe(0xd0c4b16dL), +tobe(0xe70bcf17L), tobe(0x35120ecbL), tobe(0x47f95118L), tobe(0x95e090c4L), +tobe(0x2867adecL), tobe(0xfa7e6c30L), tobe(0x889533e3L), tobe(0x5a8cf23fL), +tobe(0x6d438c45L), tobe(0xbf5a4d99L), tobe(0xcdb1124aL), tobe(0x1fa8d396L), +tobe(0xb27e75adL), tobe(0x6067b471L), tobe(0x128ceba2L), tobe(0xc0952a7eL), +tobe(0xf75a5404L), tobe(0x254395d8L), tobe(0x57a8ca0bL), tobe(0x85b10bd7L), +tobe(0x383636ffL), tobe(0xea2ff723L), tobe(0x98c4a8f0L), tobe(0x4add692cL), +tobe(0x7d121756L), tobe(0xaf0bd68aL), tobe(0xdde08959L), tobe(0x0ff94885L), +tobe(0xc3cab4d4L), tobe(0x11d37508L), tobe(0x63382adbL), tobe(0xb121eb07L), +tobe(0x86ee957dL), tobe(0x54f754a1L), tobe(0x261c0b72L), tobe(0xf405caaeL), +tobe(0x4982f786L), tobe(0x9b9b365aL), tobe(0xe9706989L), tobe(0x3b69a855L), +tobe(0x0ca6d62fL), tobe(0xdebf17f3L), tobe(0xac544820L), tobe(0x7e4d89fcL), +tobe(0xd39b2fc7L), tobe(0x0182ee1bL), tobe(0x7369b1c8L), tobe(0xa1707014L), +tobe(0x96bf0e6eL), tobe(0x44a6cfb2L), tobe(0x364d9061L), tobe(0xe45451bdL), +tobe(0x59d36c95L), tobe(0x8bcaad49L), tobe(0xf921f29aL), tobe(0x2b383346L), +tobe(0x1cf74d3cL), tobe(0xceee8ce0L), tobe(0xbc05d333L), tobe(0x6e1c12efL), +tobe(0xe36982f2L), tobe(0x3170432eL), tobe(0x439b1cfdL), tobe(0x9182dd21L), +tobe(0xa64da35bL), tobe(0x74546287L), tobe(0x06bf3d54L), tobe(0xd4a6fc88L), +tobe(0x6921c1a0L), tobe(0xbb38007cL), tobe(0xc9d35fafL), tobe(0x1bca9e73L), +tobe(0x2c05e009L), tobe(0xfe1c21d5L), tobe(0x8cf77e06L), tobe(0x5eeebfdaL), +tobe(0xf33819e1L), tobe(0x2121d83dL), tobe(0x53ca87eeL), tobe(0x81d34632L), +tobe(0xb61c3848L), tobe(0x6405f994L), tobe(0x16eea647L), tobe(0xc4f7679bL), +tobe(0x79705ab3L), tobe(0xab699b6fL), tobe(0xd982c4bcL), tobe(0x0b9b0560L), +tobe(0x3c547b1aL), tobe(0xee4dbac6L), tobe(0x9ca6e515L), tobe(0x4ebf24c9L)}, +{ +tobe(0x00000000L), tobe(0x01d8ac87L), tobe(0x03b1590eL), tobe(0x0269f589L), +tobe(0x0762b21cL), tobe(0x06ba1e9bL), tobe(0x04d3eb12L), tobe(0x050b4795L), +tobe(0x0ec56438L), tobe(0x0f1dc8bfL), tobe(0x0d743d36L), tobe(0x0cac91b1L), +tobe(0x09a7d624L), tobe(0x087f7aa3L), tobe(0x0a168f2aL), tobe(0x0bce23adL), +tobe(0x1d8ac870L), tobe(0x1c5264f7L), tobe(0x1e3b917eL), tobe(0x1fe33df9L), +tobe(0x1ae87a6cL), tobe(0x1b30d6ebL), tobe(0x19592362L), tobe(0x18818fe5L), +tobe(0x134fac48L), tobe(0x129700cfL), tobe(0x10fef546L), tobe(0x112659c1L), +tobe(0x142d1e54L), tobe(0x15f5b2d3L), tobe(0x179c475aL), tobe(0x1644ebddL), +tobe(0x3b1590e0L), tobe(0x3acd3c67L), tobe(0x38a4c9eeL), tobe(0x397c6569L), +tobe(0x3c7722fcL), tobe(0x3daf8e7bL), tobe(0x3fc67bf2L), tobe(0x3e1ed775L), +tobe(0x35d0f4d8L), tobe(0x3408585fL), tobe(0x3661add6L), tobe(0x37b90151L), +tobe(0x32b246c4L), tobe(0x336aea43L), tobe(0x31031fcaL), tobe(0x30dbb34dL), +tobe(0x269f5890L), tobe(0x2747f417L), tobe(0x252e019eL), tobe(0x24f6ad19L), +tobe(0x21fdea8cL), tobe(0x2025460bL), tobe(0x224cb382L), tobe(0x23941f05L), +tobe(0x285a3ca8L), tobe(0x2982902fL), tobe(0x2beb65a6L), tobe(0x2a33c921L), +tobe(0x2f388eb4L), tobe(0x2ee02233L), tobe(0x2c89d7baL), tobe(0x2d517b3dL), +tobe(0x762b21c0L), tobe(0x77f38d47L), tobe(0x759a78ceL), tobe(0x7442d449L), +tobe(0x714993dcL), tobe(0x70913f5bL), tobe(0x72f8cad2L), tobe(0x73206655L), +tobe(0x78ee45f8L), tobe(0x7936e97fL), tobe(0x7b5f1cf6L), tobe(0x7a87b071L), +tobe(0x7f8cf7e4L), tobe(0x7e545b63L), tobe(0x7c3daeeaL), tobe(0x7de5026dL), +tobe(0x6ba1e9b0L), tobe(0x6a794537L), tobe(0x6810b0beL), tobe(0x69c81c39L), +tobe(0x6cc35bacL), tobe(0x6d1bf72bL), tobe(0x6f7202a2L), tobe(0x6eaaae25L), +tobe(0x65648d88L), tobe(0x64bc210fL), tobe(0x66d5d486L), tobe(0x670d7801L), +tobe(0x62063f94L), tobe(0x63de9313L), tobe(0x61b7669aL), tobe(0x606fca1dL), +tobe(0x4d3eb120L), tobe(0x4ce61da7L), tobe(0x4e8fe82eL), tobe(0x4f5744a9L), +tobe(0x4a5c033cL), tobe(0x4b84afbbL), tobe(0x49ed5a32L), tobe(0x4835f6b5L), +tobe(0x43fbd518L), tobe(0x4223799fL), tobe(0x404a8c16L), tobe(0x41922091L), +tobe(0x44996704L), tobe(0x4541cb83L), tobe(0x47283e0aL), tobe(0x46f0928dL), +tobe(0x50b47950L), tobe(0x516cd5d7L), tobe(0x5305205eL), tobe(0x52dd8cd9L), +tobe(0x57d6cb4cL), tobe(0x560e67cbL), tobe(0x54679242L), tobe(0x55bf3ec5L), +tobe(0x5e711d68L), tobe(0x5fa9b1efL), tobe(0x5dc04466L), tobe(0x5c18e8e1L), +tobe(0x5913af74L), tobe(0x58cb03f3L), tobe(0x5aa2f67aL), tobe(0x5b7a5afdL), +tobe(0xec564380L), tobe(0xed8eef07L), tobe(0xefe71a8eL), tobe(0xee3fb609L), +tobe(0xeb34f19cL), tobe(0xeaec5d1bL), tobe(0xe885a892L), tobe(0xe95d0415L), +tobe(0xe29327b8L), tobe(0xe34b8b3fL), tobe(0xe1227eb6L), tobe(0xe0fad231L), +tobe(0xe5f195a4L), tobe(0xe4293923L), tobe(0xe640ccaaL), tobe(0xe798602dL), +tobe(0xf1dc8bf0L), tobe(0xf0042777L), tobe(0xf26dd2feL), tobe(0xf3b57e79L), +tobe(0xf6be39ecL), tobe(0xf766956bL), tobe(0xf50f60e2L), tobe(0xf4d7cc65L), +tobe(0xff19efc8L), tobe(0xfec1434fL), tobe(0xfca8b6c6L), tobe(0xfd701a41L), +tobe(0xf87b5dd4L), tobe(0xf9a3f153L), tobe(0xfbca04daL), tobe(0xfa12a85dL), +tobe(0xd743d360L), tobe(0xd69b7fe7L), tobe(0xd4f28a6eL), tobe(0xd52a26e9L), +tobe(0xd021617cL), tobe(0xd1f9cdfbL), tobe(0xd3903872L), tobe(0xd24894f5L), +tobe(0xd986b758L), tobe(0xd85e1bdfL), tobe(0xda37ee56L), tobe(0xdbef42d1L), +tobe(0xdee40544L), tobe(0xdf3ca9c3L), tobe(0xdd555c4aL), tobe(0xdc8df0cdL), +tobe(0xcac91b10L), tobe(0xcb11b797L), tobe(0xc978421eL), tobe(0xc8a0ee99L), +tobe(0xcdaba90cL), tobe(0xcc73058bL), tobe(0xce1af002L), tobe(0xcfc25c85L), +tobe(0xc40c7f28L), tobe(0xc5d4d3afL), tobe(0xc7bd2626L), tobe(0xc6658aa1L), +tobe(0xc36ecd34L), tobe(0xc2b661b3L), tobe(0xc0df943aL), tobe(0xc10738bdL), +tobe(0x9a7d6240L), tobe(0x9ba5cec7L), tobe(0x99cc3b4eL), tobe(0x981497c9L), +tobe(0x9d1fd05cL), tobe(0x9cc77cdbL), tobe(0x9eae8952L), tobe(0x9f7625d5L), +tobe(0x94b80678L), tobe(0x9560aaffL), tobe(0x97095f76L), tobe(0x96d1f3f1L), +tobe(0x93dab464L), tobe(0x920218e3L), tobe(0x906bed6aL), tobe(0x91b341edL), +tobe(0x87f7aa30L), tobe(0x862f06b7L), tobe(0x8446f33eL), tobe(0x859e5fb9L), +tobe(0x8095182cL), tobe(0x814db4abL), tobe(0x83244122L), tobe(0x82fceda5L), +tobe(0x8932ce08L), tobe(0x88ea628fL), tobe(0x8a839706L), tobe(0x8b5b3b81L), +tobe(0x8e507c14L), tobe(0x8f88d093L), tobe(0x8de1251aL), tobe(0x8c39899dL), +tobe(0xa168f2a0L), tobe(0xa0b05e27L), tobe(0xa2d9abaeL), tobe(0xa3010729L), +tobe(0xa60a40bcL), tobe(0xa7d2ec3bL), tobe(0xa5bb19b2L), tobe(0xa463b535L), +tobe(0xafad9698L), tobe(0xae753a1fL), tobe(0xac1ccf96L), tobe(0xadc46311L), +tobe(0xa8cf2484L), tobe(0xa9178803L), tobe(0xab7e7d8aL), tobe(0xaaa6d10dL), +tobe(0xbce23ad0L), tobe(0xbd3a9657L), tobe(0xbf5363deL), tobe(0xbe8bcf59L), +tobe(0xbb8088ccL), tobe(0xba58244bL), tobe(0xb831d1c2L), tobe(0xb9e97d45L), +tobe(0xb2275ee8L), tobe(0xb3fff26fL), tobe(0xb19607e6L), tobe(0xb04eab61L), +tobe(0xb545ecf4L), tobe(0xb49d4073L), tobe(0xb6f4b5faL), tobe(0xb72c197dL)}, +{ +tobe(0x00000000L), tobe(0xdc6d9ab7L), tobe(0xbc1a28d9L), tobe(0x6077b26eL), +tobe(0x7cf54c05L), tobe(0xa098d6b2L), tobe(0xc0ef64dcL), tobe(0x1c82fe6bL), +tobe(0xf9ea980aL), tobe(0x258702bdL), tobe(0x45f0b0d3L), tobe(0x999d2a64L), +tobe(0x851fd40fL), tobe(0x59724eb8L), tobe(0x3905fcd6L), tobe(0xe5686661L), +tobe(0xf7142da3L), tobe(0x2b79b714L), tobe(0x4b0e057aL), tobe(0x97639fcdL), +tobe(0x8be161a6L), tobe(0x578cfb11L), tobe(0x37fb497fL), tobe(0xeb96d3c8L), +tobe(0x0efeb5a9L), tobe(0xd2932f1eL), tobe(0xb2e49d70L), tobe(0x6e8907c7L), +tobe(0x720bf9acL), tobe(0xae66631bL), tobe(0xce11d175L), tobe(0x127c4bc2L), +tobe(0xeae946f1L), tobe(0x3684dc46L), tobe(0x56f36e28L), tobe(0x8a9ef49fL), +tobe(0x961c0af4L), tobe(0x4a719043L), tobe(0x2a06222dL), tobe(0xf66bb89aL), +tobe(0x1303defbL), tobe(0xcf6e444cL), tobe(0xaf19f622L), tobe(0x73746c95L), +tobe(0x6ff692feL), tobe(0xb39b0849L), tobe(0xd3ecba27L), tobe(0x0f812090L), +tobe(0x1dfd6b52L), tobe(0xc190f1e5L), tobe(0xa1e7438bL), tobe(0x7d8ad93cL), +tobe(0x61082757L), tobe(0xbd65bde0L), tobe(0xdd120f8eL), tobe(0x017f9539L), +tobe(0xe417f358L), tobe(0x387a69efL), tobe(0x580ddb81L), tobe(0x84604136L), +tobe(0x98e2bf5dL), tobe(0x448f25eaL), tobe(0x24f89784L), tobe(0xf8950d33L), +tobe(0xd1139055L), tobe(0x0d7e0ae2L), tobe(0x6d09b88cL), tobe(0xb164223bL), +tobe(0xade6dc50L), tobe(0x718b46e7L), tobe(0x11fcf489L), tobe(0xcd916e3eL), +tobe(0x28f9085fL), tobe(0xf49492e8L), tobe(0x94e32086L), tobe(0x488eba31L), +tobe(0x540c445aL), tobe(0x8861deedL), tobe(0xe8166c83L), tobe(0x347bf634L), +tobe(0x2607bdf6L), tobe(0xfa6a2741L), tobe(0x9a1d952fL), tobe(0x46700f98L), +tobe(0x5af2f1f3L), tobe(0x869f6b44L), tobe(0xe6e8d92aL), tobe(0x3a85439dL), +tobe(0xdfed25fcL), tobe(0x0380bf4bL), tobe(0x63f70d25L), tobe(0xbf9a9792L), +tobe(0xa31869f9L), tobe(0x7f75f34eL), tobe(0x1f024120L), tobe(0xc36fdb97L), +tobe(0x3bfad6a4L), tobe(0xe7974c13L), tobe(0x87e0fe7dL), tobe(0x5b8d64caL), +tobe(0x470f9aa1L), tobe(0x9b620016L), tobe(0xfb15b278L), tobe(0x277828cfL), +tobe(0xc2104eaeL), tobe(0x1e7dd419L), tobe(0x7e0a6677L), tobe(0xa267fcc0L), +tobe(0xbee502abL), tobe(0x6288981cL), tobe(0x02ff2a72L), tobe(0xde92b0c5L), +tobe(0xcceefb07L), tobe(0x108361b0L), tobe(0x70f4d3deL), tobe(0xac994969L), +tobe(0xb01bb702L), tobe(0x6c762db5L), tobe(0x0c019fdbL), tobe(0xd06c056cL), +tobe(0x3504630dL), tobe(0xe969f9baL), tobe(0x891e4bd4L), tobe(0x5573d163L), +tobe(0x49f12f08L), tobe(0x959cb5bfL), tobe(0xf5eb07d1L), tobe(0x29869d66L), +tobe(0xa6e63d1dL), tobe(0x7a8ba7aaL), tobe(0x1afc15c4L), tobe(0xc6918f73L), +tobe(0xda137118L), tobe(0x067eebafL), tobe(0x660959c1L), tobe(0xba64c376L), +tobe(0x5f0ca517L), tobe(0x83613fa0L), tobe(0xe3168dceL), tobe(0x3f7b1779L), +tobe(0x23f9e912L), tobe(0xff9473a5L), tobe(0x9fe3c1cbL), tobe(0x438e5b7cL), +tobe(0x51f210beL), tobe(0x8d9f8a09L), tobe(0xede83867L), tobe(0x3185a2d0L), +tobe(0x2d075cbbL), tobe(0xf16ac60cL), tobe(0x911d7462L), tobe(0x4d70eed5L), +tobe(0xa81888b4L), tobe(0x74751203L), tobe(0x1402a06dL), tobe(0xc86f3adaL), +tobe(0xd4edc4b1L), tobe(0x08805e06L), tobe(0x68f7ec68L), tobe(0xb49a76dfL), +tobe(0x4c0f7becL), tobe(0x9062e15bL), tobe(0xf0155335L), tobe(0x2c78c982L), +tobe(0x30fa37e9L), tobe(0xec97ad5eL), tobe(0x8ce01f30L), tobe(0x508d8587L), +tobe(0xb5e5e3e6L), tobe(0x69887951L), tobe(0x09ffcb3fL), tobe(0xd5925188L), +tobe(0xc910afe3L), tobe(0x157d3554L), tobe(0x750a873aL), tobe(0xa9671d8dL), +tobe(0xbb1b564fL), tobe(0x6776ccf8L), tobe(0x07017e96L), tobe(0xdb6ce421L), +tobe(0xc7ee1a4aL), tobe(0x1b8380fdL), tobe(0x7bf43293L), tobe(0xa799a824L), +tobe(0x42f1ce45L), tobe(0x9e9c54f2L), tobe(0xfeebe69cL), tobe(0x22867c2bL), +tobe(0x3e048240L), tobe(0xe26918f7L), tobe(0x821eaa99L), tobe(0x5e73302eL), +tobe(0x77f5ad48L), tobe(0xab9837ffL), tobe(0xcbef8591L), tobe(0x17821f26L), +tobe(0x0b00e14dL), tobe(0xd76d7bfaL), tobe(0xb71ac994L), tobe(0x6b775323L), +tobe(0x8e1f3542L), tobe(0x5272aff5L), tobe(0x32051d9bL), tobe(0xee68872cL), +tobe(0xf2ea7947L), tobe(0x2e87e3f0L), tobe(0x4ef0519eL), tobe(0x929dcb29L), +tobe(0x80e180ebL), tobe(0x5c8c1a5cL), tobe(0x3cfba832L), tobe(0xe0963285L), +tobe(0xfc14cceeL), tobe(0x20795659L), tobe(0x400ee437L), tobe(0x9c637e80L), +tobe(0x790b18e1L), tobe(0xa5668256L), tobe(0xc5113038L), tobe(0x197caa8fL), +tobe(0x05fe54e4L), tobe(0xd993ce53L), tobe(0xb9e47c3dL), tobe(0x6589e68aL), +tobe(0x9d1cebb9L), tobe(0x4171710eL), tobe(0x2106c360L), tobe(0xfd6b59d7L), +tobe(0xe1e9a7bcL), tobe(0x3d843d0bL), tobe(0x5df38f65L), tobe(0x819e15d2L), +tobe(0x64f673b3L), tobe(0xb89be904L), tobe(0xd8ec5b6aL), tobe(0x0481c1ddL), +tobe(0x18033fb6L), tobe(0xc46ea501L), tobe(0xa419176fL), tobe(0x78748dd8L), +tobe(0x6a08c61aL), tobe(0xb6655cadL), tobe(0xd612eec3L), tobe(0x0a7f7474L), +tobe(0x16fd8a1fL), tobe(0xca9010a8L), tobe(0xaae7a2c6L), tobe(0x768a3871L), +tobe(0x93e25e10L), tobe(0x4f8fc4a7L), tobe(0x2ff876c9L), tobe(0xf395ec7eL), +tobe(0xef171215L), tobe(0x337a88a2L), tobe(0x530d3accL), tobe(0x8f60a07bL)}, +{ +tobe(0x00000000L), tobe(0x490d678dL), tobe(0x921acf1aL), tobe(0xdb17a897L), +tobe(0x20f48383L), tobe(0x69f9e40eL), tobe(0xb2ee4c99L), tobe(0xfbe32b14L), +tobe(0x41e90706L), tobe(0x08e4608bL), tobe(0xd3f3c81cL), tobe(0x9afeaf91L), +tobe(0x611d8485L), tobe(0x2810e308L), tobe(0xf3074b9fL), tobe(0xba0a2c12L), +tobe(0x83d20e0cL), tobe(0xcadf6981L), tobe(0x11c8c116L), tobe(0x58c5a69bL), +tobe(0xa3268d8fL), tobe(0xea2bea02L), tobe(0x313c4295L), tobe(0x78312518L), +tobe(0xc23b090aL), tobe(0x8b366e87L), tobe(0x5021c610L), tobe(0x192ca19dL), +tobe(0xe2cf8a89L), tobe(0xabc2ed04L), tobe(0x70d54593L), tobe(0x39d8221eL), +tobe(0x036501afL), tobe(0x4a686622L), tobe(0x917fceb5L), tobe(0xd872a938L), +tobe(0x2391822cL), tobe(0x6a9ce5a1L), tobe(0xb18b4d36L), tobe(0xf8862abbL), +tobe(0x428c06a9L), tobe(0x0b816124L), tobe(0xd096c9b3L), tobe(0x999bae3eL), +tobe(0x6278852aL), tobe(0x2b75e2a7L), tobe(0xf0624a30L), tobe(0xb96f2dbdL), +tobe(0x80b70fa3L), tobe(0xc9ba682eL), tobe(0x12adc0b9L), tobe(0x5ba0a734L), +tobe(0xa0438c20L), tobe(0xe94eebadL), tobe(0x3259433aL), tobe(0x7b5424b7L), +tobe(0xc15e08a5L), tobe(0x88536f28L), tobe(0x5344c7bfL), tobe(0x1a49a032L), +tobe(0xe1aa8b26L), tobe(0xa8a7ecabL), tobe(0x73b0443cL), tobe(0x3abd23b1L), +tobe(0x06ca035eL), tobe(0x4fc764d3L), tobe(0x94d0cc44L), tobe(0xddddabc9L), +tobe(0x263e80ddL), tobe(0x6f33e750L), tobe(0xb4244fc7L), tobe(0xfd29284aL), +tobe(0x47230458L), tobe(0x0e2e63d5L), tobe(0xd539cb42L), tobe(0x9c34accfL), +tobe(0x67d787dbL), tobe(0x2edae056L), tobe(0xf5cd48c1L), tobe(0xbcc02f4cL), +tobe(0x85180d52L), tobe(0xcc156adfL), tobe(0x1702c248L), tobe(0x5e0fa5c5L), +tobe(0xa5ec8ed1L), tobe(0xece1e95cL), tobe(0x37f641cbL), tobe(0x7efb2646L), +tobe(0xc4f10a54L), tobe(0x8dfc6dd9L), tobe(0x56ebc54eL), tobe(0x1fe6a2c3L), +tobe(0xe40589d7L), tobe(0xad08ee5aL), tobe(0x761f46cdL), tobe(0x3f122140L), +tobe(0x05af02f1L), tobe(0x4ca2657cL), tobe(0x97b5cdebL), tobe(0xdeb8aa66L), +tobe(0x255b8172L), tobe(0x6c56e6ffL), tobe(0xb7414e68L), tobe(0xfe4c29e5L), +tobe(0x444605f7L), tobe(0x0d4b627aL), tobe(0xd65ccaedL), tobe(0x9f51ad60L), +tobe(0x64b28674L), tobe(0x2dbfe1f9L), tobe(0xf6a8496eL), tobe(0xbfa52ee3L), +tobe(0x867d0cfdL), tobe(0xcf706b70L), tobe(0x1467c3e7L), tobe(0x5d6aa46aL), +tobe(0xa6898f7eL), tobe(0xef84e8f3L), tobe(0x34934064L), tobe(0x7d9e27e9L), +tobe(0xc7940bfbL), tobe(0x8e996c76L), tobe(0x558ec4e1L), tobe(0x1c83a36cL), +tobe(0xe7608878L), tobe(0xae6deff5L), tobe(0x757a4762L), tobe(0x3c7720efL), +tobe(0x0d9406bcL), tobe(0x44996131L), tobe(0x9f8ec9a6L), tobe(0xd683ae2bL), +tobe(0x2d60853fL), tobe(0x646de2b2L), tobe(0xbf7a4a25L), tobe(0xf6772da8L), +tobe(0x4c7d01baL), tobe(0x05706637L), tobe(0xde67cea0L), tobe(0x976aa92dL), +tobe(0x6c898239L), tobe(0x2584e5b4L), tobe(0xfe934d23L), tobe(0xb79e2aaeL), +tobe(0x8e4608b0L), tobe(0xc74b6f3dL), tobe(0x1c5cc7aaL), tobe(0x5551a027L), +tobe(0xaeb28b33L), tobe(0xe7bfecbeL), tobe(0x3ca84429L), tobe(0x75a523a4L), +tobe(0xcfaf0fb6L), tobe(0x86a2683bL), tobe(0x5db5c0acL), tobe(0x14b8a721L), +tobe(0xef5b8c35L), tobe(0xa656ebb8L), tobe(0x7d41432fL), tobe(0x344c24a2L), +tobe(0x0ef10713L), tobe(0x47fc609eL), tobe(0x9cebc809L), tobe(0xd5e6af84L), +tobe(0x2e058490L), tobe(0x6708e31dL), tobe(0xbc1f4b8aL), tobe(0xf5122c07L), +tobe(0x4f180015L), tobe(0x06156798L), tobe(0xdd02cf0fL), tobe(0x940fa882L), +tobe(0x6fec8396L), tobe(0x26e1e41bL), tobe(0xfdf64c8cL), tobe(0xb4fb2b01L), +tobe(0x8d23091fL), tobe(0xc42e6e92L), tobe(0x1f39c605L), tobe(0x5634a188L), +tobe(0xadd78a9cL), tobe(0xe4daed11L), tobe(0x3fcd4586L), tobe(0x76c0220bL), +tobe(0xccca0e19L), tobe(0x85c76994L), tobe(0x5ed0c103L), tobe(0x17dda68eL), +tobe(0xec3e8d9aL), tobe(0xa533ea17L), tobe(0x7e244280L), tobe(0x3729250dL), +tobe(0x0b5e05e2L), tobe(0x4253626fL), tobe(0x9944caf8L), tobe(0xd049ad75L), +tobe(0x2baa8661L), tobe(0x62a7e1ecL), tobe(0xb9b0497bL), tobe(0xf0bd2ef6L), +tobe(0x4ab702e4L), tobe(0x03ba6569L), tobe(0xd8adcdfeL), tobe(0x91a0aa73L), +tobe(0x6a438167L), tobe(0x234ee6eaL), tobe(0xf8594e7dL), tobe(0xb15429f0L), +tobe(0x888c0beeL), tobe(0xc1816c63L), tobe(0x1a96c4f4L), tobe(0x539ba379L), +tobe(0xa878886dL), tobe(0xe175efe0L), tobe(0x3a624777L), tobe(0x736f20faL), +tobe(0xc9650ce8L), tobe(0x80686b65L), tobe(0x5b7fc3f2L), tobe(0x1272a47fL), +tobe(0xe9918f6bL), tobe(0xa09ce8e6L), tobe(0x7b8b4071L), tobe(0x328627fcL), +tobe(0x083b044dL), tobe(0x413663c0L), tobe(0x9a21cb57L), tobe(0xd32cacdaL), +tobe(0x28cf87ceL), tobe(0x61c2e043L), tobe(0xbad548d4L), tobe(0xf3d82f59L), +tobe(0x49d2034bL), tobe(0x00df64c6L), tobe(0xdbc8cc51L), tobe(0x92c5abdcL), +tobe(0x692680c8L), tobe(0x202be745L), tobe(0xfb3c4fd2L), tobe(0xb231285fL), +tobe(0x8be90a41L), tobe(0xc2e46dccL), tobe(0x19f3c55bL), tobe(0x50fea2d6L), +tobe(0xab1d89c2L), tobe(0xe210ee4fL), tobe(0x390746d8L), tobe(0x700a2155L), +tobe(0xca000d47L), tobe(0x830d6acaL), tobe(0x581ac25dL), tobe(0x1117a5d0L), +tobe(0xeaf48ec4L), tobe(0xa3f9e949L), tobe(0x78ee41deL), tobe(0x31e32653L)}, +{ +tobe(0x00000000L), tobe(0x1b280d78L), tobe(0x36501af0L), tobe(0x2d781788L), +tobe(0x6ca035e0L), tobe(0x77883898L), tobe(0x5af02f10L), tobe(0x41d82268L), +tobe(0xd9406bc0L), tobe(0xc26866b8L), tobe(0xef107130L), tobe(0xf4387c48L), +tobe(0xb5e05e20L), tobe(0xaec85358L), tobe(0x83b044d0L), tobe(0x989849a8L), +tobe(0xb641ca37L), tobe(0xad69c74fL), tobe(0x8011d0c7L), tobe(0x9b39ddbfL), +tobe(0xdae1ffd7L), tobe(0xc1c9f2afL), tobe(0xecb1e527L), tobe(0xf799e85fL), +tobe(0x6f01a1f7L), tobe(0x7429ac8fL), tobe(0x5951bb07L), tobe(0x4279b67fL), +tobe(0x03a19417L), tobe(0x1889996fL), tobe(0x35f18ee7L), tobe(0x2ed9839fL), +tobe(0x684289d9L), tobe(0x736a84a1L), tobe(0x5e129329L), tobe(0x453a9e51L), +tobe(0x04e2bc39L), tobe(0x1fcab141L), tobe(0x32b2a6c9L), tobe(0x299aabb1L), +tobe(0xb102e219L), tobe(0xaa2aef61L), tobe(0x8752f8e9L), tobe(0x9c7af591L), +tobe(0xdda2d7f9L), tobe(0xc68ada81L), tobe(0xebf2cd09L), tobe(0xf0dac071L), +tobe(0xde0343eeL), tobe(0xc52b4e96L), tobe(0xe853591eL), tobe(0xf37b5466L), +tobe(0xb2a3760eL), tobe(0xa98b7b76L), tobe(0x84f36cfeL), tobe(0x9fdb6186L), +tobe(0x0743282eL), tobe(0x1c6b2556L), tobe(0x311332deL), tobe(0x2a3b3fa6L), +tobe(0x6be31dceL), tobe(0x70cb10b6L), tobe(0x5db3073eL), tobe(0x469b0a46L), +tobe(0xd08513b2L), tobe(0xcbad1ecaL), tobe(0xe6d50942L), tobe(0xfdfd043aL), +tobe(0xbc252652L), tobe(0xa70d2b2aL), tobe(0x8a753ca2L), tobe(0x915d31daL), +tobe(0x09c57872L), tobe(0x12ed750aL), tobe(0x3f956282L), tobe(0x24bd6ffaL), +tobe(0x65654d92L), tobe(0x7e4d40eaL), tobe(0x53355762L), tobe(0x481d5a1aL), +tobe(0x66c4d985L), tobe(0x7decd4fdL), tobe(0x5094c375L), tobe(0x4bbcce0dL), +tobe(0x0a64ec65L), tobe(0x114ce11dL), tobe(0x3c34f695L), tobe(0x271cfbedL), +tobe(0xbf84b245L), tobe(0xa4acbf3dL), tobe(0x89d4a8b5L), tobe(0x92fca5cdL), +tobe(0xd32487a5L), tobe(0xc80c8addL), tobe(0xe5749d55L), tobe(0xfe5c902dL), +tobe(0xb8c79a6bL), tobe(0xa3ef9713L), tobe(0x8e97809bL), tobe(0x95bf8de3L), +tobe(0xd467af8bL), tobe(0xcf4fa2f3L), tobe(0xe237b57bL), tobe(0xf91fb803L), +tobe(0x6187f1abL), tobe(0x7aaffcd3L), tobe(0x57d7eb5bL), tobe(0x4cffe623L), +tobe(0x0d27c44bL), tobe(0x160fc933L), tobe(0x3b77debbL), tobe(0x205fd3c3L), +tobe(0x0e86505cL), tobe(0x15ae5d24L), tobe(0x38d64aacL), tobe(0x23fe47d4L), +tobe(0x622665bcL), tobe(0x790e68c4L), tobe(0x54767f4cL), tobe(0x4f5e7234L), +tobe(0xd7c63b9cL), tobe(0xccee36e4L), tobe(0xe196216cL), tobe(0xfabe2c14L), +tobe(0xbb660e7cL), tobe(0xa04e0304L), tobe(0x8d36148cL), tobe(0x961e19f4L), +tobe(0xa5cb3ad3L), tobe(0xbee337abL), tobe(0x939b2023L), tobe(0x88b32d5bL), +tobe(0xc96b0f33L), tobe(0xd243024bL), tobe(0xff3b15c3L), tobe(0xe41318bbL), +tobe(0x7c8b5113L), tobe(0x67a35c6bL), tobe(0x4adb4be3L), tobe(0x51f3469bL), +tobe(0x102b64f3L), tobe(0x0b03698bL), tobe(0x267b7e03L), tobe(0x3d53737bL), +tobe(0x138af0e4L), tobe(0x08a2fd9cL), tobe(0x25daea14L), tobe(0x3ef2e76cL), +tobe(0x7f2ac504L), tobe(0x6402c87cL), tobe(0x497adff4L), tobe(0x5252d28cL), +tobe(0xcaca9b24L), tobe(0xd1e2965cL), tobe(0xfc9a81d4L), tobe(0xe7b28cacL), +tobe(0xa66aaec4L), tobe(0xbd42a3bcL), tobe(0x903ab434L), tobe(0x8b12b94cL), +tobe(0xcd89b30aL), tobe(0xd6a1be72L), tobe(0xfbd9a9faL), tobe(0xe0f1a482L), +tobe(0xa12986eaL), tobe(0xba018b92L), tobe(0x97799c1aL), tobe(0x8c519162L), +tobe(0x14c9d8caL), tobe(0x0fe1d5b2L), tobe(0x2299c23aL), tobe(0x39b1cf42L), +tobe(0x7869ed2aL), tobe(0x6341e052L), tobe(0x4e39f7daL), tobe(0x5511faa2L), +tobe(0x7bc8793dL), tobe(0x60e07445L), tobe(0x4d9863cdL), tobe(0x56b06eb5L), +tobe(0x17684cddL), tobe(0x0c4041a5L), tobe(0x2138562dL), tobe(0x3a105b55L), +tobe(0xa28812fdL), tobe(0xb9a01f85L), tobe(0x94d8080dL), tobe(0x8ff00575L), +tobe(0xce28271dL), tobe(0xd5002a65L), tobe(0xf8783dedL), tobe(0xe3503095L), +tobe(0x754e2961L), tobe(0x6e662419L), tobe(0x431e3391L), tobe(0x58363ee9L), +tobe(0x19ee1c81L), tobe(0x02c611f9L), tobe(0x2fbe0671L), tobe(0x34960b09L), +tobe(0xac0e42a1L), tobe(0xb7264fd9L), tobe(0x9a5e5851L), tobe(0x81765529L), +tobe(0xc0ae7741L), tobe(0xdb867a39L), tobe(0xf6fe6db1L), tobe(0xedd660c9L), +tobe(0xc30fe356L), tobe(0xd827ee2eL), tobe(0xf55ff9a6L), tobe(0xee77f4deL), +tobe(0xafafd6b6L), tobe(0xb487dbceL), tobe(0x99ffcc46L), tobe(0x82d7c13eL), +tobe(0x1a4f8896L), tobe(0x016785eeL), tobe(0x2c1f9266L), tobe(0x37379f1eL), +tobe(0x76efbd76L), tobe(0x6dc7b00eL), tobe(0x40bfa786L), tobe(0x5b97aafeL), +tobe(0x1d0ca0b8L), tobe(0x0624adc0L), tobe(0x2b5cba48L), tobe(0x3074b730L), +tobe(0x71ac9558L), tobe(0x6a849820L), tobe(0x47fc8fa8L), tobe(0x5cd482d0L), +tobe(0xc44ccb78L), tobe(0xdf64c600L), tobe(0xf21cd188L), tobe(0xe934dcf0L), +tobe(0xa8ecfe98L), tobe(0xb3c4f3e0L), tobe(0x9ebce468L), tobe(0x8594e910L), +tobe(0xab4d6a8fL), tobe(0xb06567f7L), tobe(0x9d1d707fL), tobe(0x86357d07L), +tobe(0xc7ed5f6fL), tobe(0xdcc55217L), tobe(0xf1bd459fL), tobe(0xea9548e7L), +tobe(0x720d014fL), tobe(0x69250c37L), tobe(0x445d1bbfL), tobe(0x5f7516c7L), +tobe(0x1ead34afL), tobe(0x058539d7L), tobe(0x28fd2e5fL), tobe(0x33d52327L)}, +{ +tobe(0x00000000L), tobe(0x4f576811L), tobe(0x9eaed022L), tobe(0xd1f9b833L), +tobe(0x399cbdf3L), tobe(0x76cbd5e2L), tobe(0xa7326dd1L), tobe(0xe86505c0L), +tobe(0x73397be6L), tobe(0x3c6e13f7L), tobe(0xed97abc4L), tobe(0xa2c0c3d5L), +tobe(0x4aa5c615L), tobe(0x05f2ae04L), tobe(0xd40b1637L), tobe(0x9b5c7e26L), +tobe(0xe672f7ccL), tobe(0xa9259fddL), tobe(0x78dc27eeL), tobe(0x378b4fffL), +tobe(0xdfee4a3fL), tobe(0x90b9222eL), tobe(0x41409a1dL), tobe(0x0e17f20cL), +tobe(0x954b8c2aL), tobe(0xda1ce43bL), tobe(0x0be55c08L), tobe(0x44b23419L), +tobe(0xacd731d9L), tobe(0xe38059c8L), tobe(0x3279e1fbL), tobe(0x7d2e89eaL), +tobe(0xc824f22fL), tobe(0x87739a3eL), tobe(0x568a220dL), tobe(0x19dd4a1cL), +tobe(0xf1b84fdcL), tobe(0xbeef27cdL), tobe(0x6f169ffeL), tobe(0x2041f7efL), +tobe(0xbb1d89c9L), tobe(0xf44ae1d8L), tobe(0x25b359ebL), tobe(0x6ae431faL), +tobe(0x8281343aL), tobe(0xcdd65c2bL), tobe(0x1c2fe418L), tobe(0x53788c09L), +tobe(0x2e5605e3L), tobe(0x61016df2L), tobe(0xb0f8d5c1L), tobe(0xffafbdd0L), +tobe(0x17cab810L), tobe(0x589dd001L), tobe(0x89646832L), tobe(0xc6330023L), +tobe(0x5d6f7e05L), tobe(0x12381614L), tobe(0xc3c1ae27L), tobe(0x8c96c636L), +tobe(0x64f3c3f6L), tobe(0x2ba4abe7L), tobe(0xfa5d13d4L), tobe(0xb50a7bc5L), +tobe(0x9488f9e9L), tobe(0xdbdf91f8L), tobe(0x0a2629cbL), tobe(0x457141daL), +tobe(0xad14441aL), tobe(0xe2432c0bL), tobe(0x33ba9438L), tobe(0x7cedfc29L), +tobe(0xe7b1820fL), tobe(0xa8e6ea1eL), tobe(0x791f522dL), tobe(0x36483a3cL), +tobe(0xde2d3ffcL), tobe(0x917a57edL), tobe(0x4083efdeL), tobe(0x0fd487cfL), +tobe(0x72fa0e25L), tobe(0x3dad6634L), tobe(0xec54de07L), tobe(0xa303b616L), +tobe(0x4b66b3d6L), tobe(0x0431dbc7L), tobe(0xd5c863f4L), tobe(0x9a9f0be5L), +tobe(0x01c375c3L), tobe(0x4e941dd2L), tobe(0x9f6da5e1L), tobe(0xd03acdf0L), +tobe(0x385fc830L), tobe(0x7708a021L), tobe(0xa6f11812L), tobe(0xe9a67003L), +tobe(0x5cac0bc6L), tobe(0x13fb63d7L), tobe(0xc202dbe4L), tobe(0x8d55b3f5L), +tobe(0x6530b635L), tobe(0x2a67de24L), tobe(0xfb9e6617L), tobe(0xb4c90e06L), +tobe(0x2f957020L), tobe(0x60c21831L), tobe(0xb13ba002L), tobe(0xfe6cc813L), +tobe(0x1609cdd3L), tobe(0x595ea5c2L), tobe(0x88a71df1L), tobe(0xc7f075e0L), +tobe(0xbadefc0aL), tobe(0xf589941bL), tobe(0x24702c28L), tobe(0x6b274439L), +tobe(0x834241f9L), tobe(0xcc1529e8L), tobe(0x1dec91dbL), tobe(0x52bbf9caL), +tobe(0xc9e787ecL), tobe(0x86b0effdL), tobe(0x574957ceL), tobe(0x181e3fdfL), +tobe(0xf07b3a1fL), tobe(0xbf2c520eL), tobe(0x6ed5ea3dL), tobe(0x2182822cL), +tobe(0x2dd0ee65L), tobe(0x62878674L), tobe(0xb37e3e47L), tobe(0xfc295656L), +tobe(0x144c5396L), tobe(0x5b1b3b87L), tobe(0x8ae283b4L), tobe(0xc5b5eba5L), +tobe(0x5ee99583L), tobe(0x11befd92L), tobe(0xc04745a1L), tobe(0x8f102db0L), +tobe(0x67752870L), tobe(0x28224061L), tobe(0xf9dbf852L), tobe(0xb68c9043L), +tobe(0xcba219a9L), tobe(0x84f571b8L), tobe(0x550cc98bL), tobe(0x1a5ba19aL), +tobe(0xf23ea45aL), tobe(0xbd69cc4bL), tobe(0x6c907478L), tobe(0x23c71c69L), +tobe(0xb89b624fL), tobe(0xf7cc0a5eL), tobe(0x2635b26dL), tobe(0x6962da7cL), +tobe(0x8107dfbcL), tobe(0xce50b7adL), tobe(0x1fa90f9eL), tobe(0x50fe678fL), +tobe(0xe5f41c4aL), tobe(0xaaa3745bL), tobe(0x7b5acc68L), tobe(0x340da479L), +tobe(0xdc68a1b9L), tobe(0x933fc9a8L), tobe(0x42c6719bL), tobe(0x0d91198aL), +tobe(0x96cd67acL), tobe(0xd99a0fbdL), tobe(0x0863b78eL), tobe(0x4734df9fL), +tobe(0xaf51da5fL), tobe(0xe006b24eL), tobe(0x31ff0a7dL), tobe(0x7ea8626cL), +tobe(0x0386eb86L), tobe(0x4cd18397L), tobe(0x9d283ba4L), tobe(0xd27f53b5L), +tobe(0x3a1a5675L), tobe(0x754d3e64L), tobe(0xa4b48657L), tobe(0xebe3ee46L), +tobe(0x70bf9060L), tobe(0x3fe8f871L), tobe(0xee114042L), tobe(0xa1462853L), +tobe(0x49232d93L), tobe(0x06744582L), tobe(0xd78dfdb1L), tobe(0x98da95a0L), +tobe(0xb958178cL), tobe(0xf60f7f9dL), tobe(0x27f6c7aeL), tobe(0x68a1afbfL), +tobe(0x80c4aa7fL), tobe(0xcf93c26eL), tobe(0x1e6a7a5dL), tobe(0x513d124cL), +tobe(0xca616c6aL), tobe(0x8536047bL), tobe(0x54cfbc48L), tobe(0x1b98d459L), +tobe(0xf3fdd199L), tobe(0xbcaab988L), tobe(0x6d5301bbL), tobe(0x220469aaL), +tobe(0x5f2ae040L), tobe(0x107d8851L), tobe(0xc1843062L), tobe(0x8ed35873L), +tobe(0x66b65db3L), tobe(0x29e135a2L), tobe(0xf8188d91L), tobe(0xb74fe580L), +tobe(0x2c139ba6L), tobe(0x6344f3b7L), tobe(0xb2bd4b84L), tobe(0xfdea2395L), +tobe(0x158f2655L), tobe(0x5ad84e44L), tobe(0x8b21f677L), tobe(0xc4769e66L), +tobe(0x717ce5a3L), tobe(0x3e2b8db2L), tobe(0xefd23581L), tobe(0xa0855d90L), +tobe(0x48e05850L), tobe(0x07b73041L), tobe(0xd64e8872L), tobe(0x9919e063L), +tobe(0x02459e45L), tobe(0x4d12f654L), tobe(0x9ceb4e67L), tobe(0xd3bc2676L), +tobe(0x3bd923b6L), tobe(0x748e4ba7L), tobe(0xa577f394L), tobe(0xea209b85L), +tobe(0x970e126fL), tobe(0xd8597a7eL), tobe(0x09a0c24dL), tobe(0x46f7aa5cL), +tobe(0xae92af9cL), tobe(0xe1c5c78dL), tobe(0x303c7fbeL), tobe(0x7f6b17afL), +tobe(0xe4376989L), tobe(0xab600198L), tobe(0x7a99b9abL), tobe(0x35ced1baL), +tobe(0xddabd47aL), tobe(0x92fcbc6bL), tobe(0x43050458L), tobe(0x0c526c49L)}, +{ +tobe(0x00000000L), tobe(0x5ba1dccaL), tobe(0xb743b994L), tobe(0xece2655eL), +tobe(0x6a466e9fL), tobe(0x31e7b255L), tobe(0xdd05d70bL), tobe(0x86a40bc1L), +tobe(0xd48cdd3eL), tobe(0x8f2d01f4L), tobe(0x63cf64aaL), tobe(0x386eb860L), +tobe(0xbecab3a1L), tobe(0xe56b6f6bL), tobe(0x09890a35L), tobe(0x5228d6ffL), +tobe(0xadd8a7cbL), tobe(0xf6797b01L), tobe(0x1a9b1e5fL), tobe(0x413ac295L), +tobe(0xc79ec954L), tobe(0x9c3f159eL), tobe(0x70dd70c0L), tobe(0x2b7cac0aL), +tobe(0x79547af5L), tobe(0x22f5a63fL), tobe(0xce17c361L), tobe(0x95b61fabL), +tobe(0x1312146aL), tobe(0x48b3c8a0L), tobe(0xa451adfeL), tobe(0xfff07134L), +tobe(0x5f705221L), tobe(0x04d18eebL), tobe(0xe833ebb5L), tobe(0xb392377fL), +tobe(0x35363cbeL), tobe(0x6e97e074L), tobe(0x8275852aL), tobe(0xd9d459e0L), +tobe(0x8bfc8f1fL), tobe(0xd05d53d5L), tobe(0x3cbf368bL), tobe(0x671eea41L), +tobe(0xe1bae180L), tobe(0xba1b3d4aL), tobe(0x56f95814L), tobe(0x0d5884deL), +tobe(0xf2a8f5eaL), tobe(0xa9092920L), tobe(0x45eb4c7eL), tobe(0x1e4a90b4L), +tobe(0x98ee9b75L), tobe(0xc34f47bfL), tobe(0x2fad22e1L), tobe(0x740cfe2bL), +tobe(0x262428d4L), tobe(0x7d85f41eL), tobe(0x91679140L), tobe(0xcac64d8aL), +tobe(0x4c62464bL), tobe(0x17c39a81L), tobe(0xfb21ffdfL), tobe(0xa0802315L), +tobe(0xbee0a442L), tobe(0xe5417888L), tobe(0x09a31dd6L), tobe(0x5202c11cL), +tobe(0xd4a6caddL), tobe(0x8f071617L), tobe(0x63e57349L), tobe(0x3844af83L), +tobe(0x6a6c797cL), tobe(0x31cda5b6L), tobe(0xdd2fc0e8L), tobe(0x868e1c22L), +tobe(0x002a17e3L), tobe(0x5b8bcb29L), tobe(0xb769ae77L), tobe(0xecc872bdL), +tobe(0x13380389L), tobe(0x4899df43L), tobe(0xa47bba1dL), tobe(0xffda66d7L), +tobe(0x797e6d16L), tobe(0x22dfb1dcL), tobe(0xce3dd482L), tobe(0x959c0848L), +tobe(0xc7b4deb7L), tobe(0x9c15027dL), tobe(0x70f76723L), tobe(0x2b56bbe9L), +tobe(0xadf2b028L), tobe(0xf6536ce2L), tobe(0x1ab109bcL), tobe(0x4110d576L), +tobe(0xe190f663L), tobe(0xba312aa9L), tobe(0x56d34ff7L), tobe(0x0d72933dL), +tobe(0x8bd698fcL), tobe(0xd0774436L), tobe(0x3c952168L), tobe(0x6734fda2L), +tobe(0x351c2b5dL), tobe(0x6ebdf797L), tobe(0x825f92c9L), tobe(0xd9fe4e03L), +tobe(0x5f5a45c2L), tobe(0x04fb9908L), tobe(0xe819fc56L), tobe(0xb3b8209cL), +tobe(0x4c4851a8L), tobe(0x17e98d62L), tobe(0xfb0be83cL), tobe(0xa0aa34f6L), +tobe(0x260e3f37L), tobe(0x7dafe3fdL), tobe(0x914d86a3L), tobe(0xcaec5a69L), +tobe(0x98c48c96L), tobe(0xc365505cL), tobe(0x2f873502L), tobe(0x7426e9c8L), +tobe(0xf282e209L), tobe(0xa9233ec3L), tobe(0x45c15b9dL), tobe(0x1e608757L), +tobe(0x79005533L), tobe(0x22a189f9L), tobe(0xce43eca7L), tobe(0x95e2306dL), +tobe(0x13463bacL), tobe(0x48e7e766L), tobe(0xa4058238L), tobe(0xffa45ef2L), +tobe(0xad8c880dL), tobe(0xf62d54c7L), tobe(0x1acf3199L), tobe(0x416eed53L), +tobe(0xc7cae692L), tobe(0x9c6b3a58L), tobe(0x70895f06L), tobe(0x2b2883ccL), +tobe(0xd4d8f2f8L), tobe(0x8f792e32L), tobe(0x639b4b6cL), tobe(0x383a97a6L), +tobe(0xbe9e9c67L), tobe(0xe53f40adL), tobe(0x09dd25f3L), tobe(0x527cf939L), +tobe(0x00542fc6L), tobe(0x5bf5f30cL), tobe(0xb7179652L), tobe(0xecb64a98L), +tobe(0x6a124159L), tobe(0x31b39d93L), tobe(0xdd51f8cdL), tobe(0x86f02407L), +tobe(0x26700712L), tobe(0x7dd1dbd8L), tobe(0x9133be86L), tobe(0xca92624cL), +tobe(0x4c36698dL), tobe(0x1797b547L), tobe(0xfb75d019L), tobe(0xa0d40cd3L), +tobe(0xf2fcda2cL), tobe(0xa95d06e6L), tobe(0x45bf63b8L), tobe(0x1e1ebf72L), +tobe(0x98bab4b3L), tobe(0xc31b6879L), tobe(0x2ff90d27L), tobe(0x7458d1edL), +tobe(0x8ba8a0d9L), tobe(0xd0097c13L), tobe(0x3ceb194dL), tobe(0x674ac587L), +tobe(0xe1eece46L), tobe(0xba4f128cL), tobe(0x56ad77d2L), tobe(0x0d0cab18L), +tobe(0x5f247de7L), tobe(0x0485a12dL), tobe(0xe867c473L), tobe(0xb3c618b9L), +tobe(0x35621378L), tobe(0x6ec3cfb2L), tobe(0x8221aaecL), tobe(0xd9807626L), +tobe(0xc7e0f171L), tobe(0x9c412dbbL), tobe(0x70a348e5L), tobe(0x2b02942fL), +tobe(0xada69feeL), tobe(0xf6074324L), tobe(0x1ae5267aL), tobe(0x4144fab0L), +tobe(0x136c2c4fL), tobe(0x48cdf085L), tobe(0xa42f95dbL), tobe(0xff8e4911L), +tobe(0x792a42d0L), tobe(0x228b9e1aL), tobe(0xce69fb44L), tobe(0x95c8278eL), +tobe(0x6a3856baL), tobe(0x31998a70L), tobe(0xdd7bef2eL), tobe(0x86da33e4L), +tobe(0x007e3825L), tobe(0x5bdfe4efL), tobe(0xb73d81b1L), tobe(0xec9c5d7bL), +tobe(0xbeb48b84L), tobe(0xe515574eL), tobe(0x09f73210L), tobe(0x5256eedaL), +tobe(0xd4f2e51bL), tobe(0x8f5339d1L), tobe(0x63b15c8fL), tobe(0x38108045L), +tobe(0x9890a350L), tobe(0xc3317f9aL), tobe(0x2fd31ac4L), tobe(0x7472c60eL), +tobe(0xf2d6cdcfL), tobe(0xa9771105L), tobe(0x4595745bL), tobe(0x1e34a891L), +tobe(0x4c1c7e6eL), tobe(0x17bda2a4L), tobe(0xfb5fc7faL), tobe(0xa0fe1b30L), +tobe(0x265a10f1L), tobe(0x7dfbcc3bL), tobe(0x9119a965L), tobe(0xcab875afL), +tobe(0x3548049bL), tobe(0x6ee9d851L), tobe(0x820bbd0fL), tobe(0xd9aa61c5L), +tobe(0x5f0e6a04L), tobe(0x04afb6ceL), tobe(0xe84dd390L), tobe(0xb3ec0f5aL), +tobe(0xe1c4d9a5L), tobe(0xba65056fL), tobe(0x56876031L), tobe(0x0d26bcfbL), +tobe(0x8b82b73aL), tobe(0xd0236bf0L), tobe(0x3cc10eaeL), tobe(0x6760d264L)}, +}; +static const uint32_t crc32ctable_le[8][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)}, +{ +tole(0x00000000L), tole(0x38116facL), tole(0x7022df58L), tole(0x4833b0f4L), +tole(0xe045beb0L), tole(0xd854d11cL), tole(0x906761e8L), tole(0xa8760e44L), +tole(0xc5670b91L), tole(0xfd76643dL), tole(0xb545d4c9L), tole(0x8d54bb65L), +tole(0x2522b521L), tole(0x1d33da8dL), tole(0x55006a79L), tole(0x6d1105d5L), +tole(0x8f2261d3L), tole(0xb7330e7fL), tole(0xff00be8bL), tole(0xc711d127L), +tole(0x6f67df63L), tole(0x5776b0cfL), tole(0x1f45003bL), tole(0x27546f97L), +tole(0x4a456a42L), tole(0x725405eeL), tole(0x3a67b51aL), tole(0x0276dab6L), +tole(0xaa00d4f2L), tole(0x9211bb5eL), tole(0xda220baaL), tole(0xe2336406L), +tole(0x1ba8b557L), tole(0x23b9dafbL), tole(0x6b8a6a0fL), tole(0x539b05a3L), +tole(0xfbed0be7L), tole(0xc3fc644bL), tole(0x8bcfd4bfL), tole(0xb3debb13L), +tole(0xdecfbec6L), tole(0xe6ded16aL), tole(0xaeed619eL), tole(0x96fc0e32L), +tole(0x3e8a0076L), tole(0x069b6fdaL), tole(0x4ea8df2eL), tole(0x76b9b082L), +tole(0x948ad484L), tole(0xac9bbb28L), tole(0xe4a80bdcL), tole(0xdcb96470L), +tole(0x74cf6a34L), tole(0x4cde0598L), tole(0x04edb56cL), tole(0x3cfcdac0L), +tole(0x51eddf15L), tole(0x69fcb0b9L), tole(0x21cf004dL), tole(0x19de6fe1L), +tole(0xb1a861a5L), tole(0x89b90e09L), tole(0xc18abefdL), tole(0xf99bd151L), +tole(0x37516aaeL), tole(0x0f400502L), tole(0x4773b5f6L), tole(0x7f62da5aL), +tole(0xd714d41eL), tole(0xef05bbb2L), tole(0xa7360b46L), tole(0x9f2764eaL), +tole(0xf236613fL), tole(0xca270e93L), tole(0x8214be67L), tole(0xba05d1cbL), +tole(0x1273df8fL), tole(0x2a62b023L), tole(0x625100d7L), tole(0x5a406f7bL), +tole(0xb8730b7dL), tole(0x806264d1L), tole(0xc851d425L), tole(0xf040bb89L), +tole(0x5836b5cdL), tole(0x6027da61L), tole(0x28146a95L), tole(0x10050539L), +tole(0x7d1400ecL), tole(0x45056f40L), tole(0x0d36dfb4L), tole(0x3527b018L), +tole(0x9d51be5cL), tole(0xa540d1f0L), tole(0xed736104L), tole(0xd5620ea8L), +tole(0x2cf9dff9L), tole(0x14e8b055L), tole(0x5cdb00a1L), tole(0x64ca6f0dL), +tole(0xccbc6149L), tole(0xf4ad0ee5L), tole(0xbc9ebe11L), tole(0x848fd1bdL), +tole(0xe99ed468L), tole(0xd18fbbc4L), tole(0x99bc0b30L), tole(0xa1ad649cL), +tole(0x09db6ad8L), tole(0x31ca0574L), tole(0x79f9b580L), tole(0x41e8da2cL), +tole(0xa3dbbe2aL), tole(0x9bcad186L), tole(0xd3f96172L), tole(0xebe80edeL), +tole(0x439e009aL), tole(0x7b8f6f36L), tole(0x33bcdfc2L), tole(0x0badb06eL), +tole(0x66bcb5bbL), tole(0x5eadda17L), tole(0x169e6ae3L), tole(0x2e8f054fL), +tole(0x86f90b0bL), tole(0xbee864a7L), tole(0xf6dbd453L), tole(0xcecabbffL), +tole(0x6ea2d55cL), tole(0x56b3baf0L), tole(0x1e800a04L), tole(0x269165a8L), +tole(0x8ee76becL), tole(0xb6f60440L), tole(0xfec5b4b4L), tole(0xc6d4db18L), +tole(0xabc5decdL), tole(0x93d4b161L), tole(0xdbe70195L), tole(0xe3f66e39L), +tole(0x4b80607dL), tole(0x73910fd1L), tole(0x3ba2bf25L), tole(0x03b3d089L), +tole(0xe180b48fL), tole(0xd991db23L), tole(0x91a26bd7L), tole(0xa9b3047bL), +tole(0x01c50a3fL), tole(0x39d46593L), tole(0x71e7d567L), tole(0x49f6bacbL), +tole(0x24e7bf1eL), tole(0x1cf6d0b2L), tole(0x54c56046L), tole(0x6cd40feaL), +tole(0xc4a201aeL), tole(0xfcb36e02L), tole(0xb480def6L), tole(0x8c91b15aL), +tole(0x750a600bL), tole(0x4d1b0fa7L), tole(0x0528bf53L), tole(0x3d39d0ffL), +tole(0x954fdebbL), tole(0xad5eb117L), tole(0xe56d01e3L), tole(0xdd7c6e4fL), +tole(0xb06d6b9aL), tole(0x887c0436L), tole(0xc04fb4c2L), tole(0xf85edb6eL), +tole(0x5028d52aL), tole(0x6839ba86L), tole(0x200a0a72L), tole(0x181b65deL), +tole(0xfa2801d8L), tole(0xc2396e74L), tole(0x8a0ade80L), tole(0xb21bb12cL), +tole(0x1a6dbf68L), tole(0x227cd0c4L), tole(0x6a4f6030L), tole(0x525e0f9cL), +tole(0x3f4f0a49L), tole(0x075e65e5L), tole(0x4f6dd511L), tole(0x777cbabdL), +tole(0xdf0ab4f9L), tole(0xe71bdb55L), tole(0xaf286ba1L), tole(0x9739040dL), +tole(0x59f3bff2L), tole(0x61e2d05eL), tole(0x29d160aaL), tole(0x11c00f06L), +tole(0xb9b60142L), tole(0x81a76eeeL), tole(0xc994de1aL), tole(0xf185b1b6L), +tole(0x9c94b463L), tole(0xa485dbcfL), tole(0xecb66b3bL), tole(0xd4a70497L), +tole(0x7cd10ad3L), tole(0x44c0657fL), tole(0x0cf3d58bL), tole(0x34e2ba27L), +tole(0xd6d1de21L), tole(0xeec0b18dL), tole(0xa6f30179L), tole(0x9ee26ed5L), +tole(0x36946091L), tole(0x0e850f3dL), tole(0x46b6bfc9L), tole(0x7ea7d065L), +tole(0x13b6d5b0L), tole(0x2ba7ba1cL), tole(0x63940ae8L), tole(0x5b856544L), +tole(0xf3f36b00L), tole(0xcbe204acL), tole(0x83d1b458L), tole(0xbbc0dbf4L), +tole(0x425b0aa5L), tole(0x7a4a6509L), tole(0x3279d5fdL), tole(0x0a68ba51L), +tole(0xa21eb415L), tole(0x9a0fdbb9L), tole(0xd23c6b4dL), tole(0xea2d04e1L), +tole(0x873c0134L), tole(0xbf2d6e98L), tole(0xf71ede6cL), tole(0xcf0fb1c0L), +tole(0x6779bf84L), tole(0x5f68d028L), tole(0x175b60dcL), tole(0x2f4a0f70L), +tole(0xcd796b76L), tole(0xf56804daL), tole(0xbd5bb42eL), tole(0x854adb82L), +tole(0x2d3cd5c6L), tole(0x152dba6aL), tole(0x5d1e0a9eL), tole(0x650f6532L), +tole(0x081e60e7L), tole(0x300f0f4bL), tole(0x783cbfbfL), tole(0x402dd013L), +tole(0xe85bde57L), tole(0xd04ab1fbL), tole(0x9879010fL), tole(0xa0686ea3L)}, +{ +tole(0x00000000L), tole(0xef306b19L), tole(0xdb8ca0c3L), tole(0x34bccbdaL), +tole(0xb2f53777L), tole(0x5dc55c6eL), tole(0x697997b4L), tole(0x8649fcadL), +tole(0x6006181fL), tole(0x8f367306L), tole(0xbb8ab8dcL), tole(0x54bad3c5L), +tole(0xd2f32f68L), tole(0x3dc34471L), tole(0x097f8fabL), tole(0xe64fe4b2L), +tole(0xc00c303eL), tole(0x2f3c5b27L), tole(0x1b8090fdL), tole(0xf4b0fbe4L), +tole(0x72f90749L), tole(0x9dc96c50L), tole(0xa975a78aL), tole(0x4645cc93L), +tole(0xa00a2821L), tole(0x4f3a4338L), tole(0x7b8688e2L), tole(0x94b6e3fbL), +tole(0x12ff1f56L), tole(0xfdcf744fL), tole(0xc973bf95L), tole(0x2643d48cL), +tole(0x85f4168dL), tole(0x6ac47d94L), tole(0x5e78b64eL), tole(0xb148dd57L), +tole(0x370121faL), tole(0xd8314ae3L), tole(0xec8d8139L), tole(0x03bdea20L), +tole(0xe5f20e92L), tole(0x0ac2658bL), tole(0x3e7eae51L), tole(0xd14ec548L), +tole(0x570739e5L), tole(0xb83752fcL), tole(0x8c8b9926L), tole(0x63bbf23fL), +tole(0x45f826b3L), tole(0xaac84daaL), tole(0x9e748670L), tole(0x7144ed69L), +tole(0xf70d11c4L), tole(0x183d7addL), tole(0x2c81b107L), tole(0xc3b1da1eL), +tole(0x25fe3eacL), tole(0xcace55b5L), tole(0xfe729e6fL), tole(0x1142f576L), +tole(0x970b09dbL), tole(0x783b62c2L), tole(0x4c87a918L), tole(0xa3b7c201L), +tole(0x0e045bebL), tole(0xe13430f2L), tole(0xd588fb28L), tole(0x3ab89031L), +tole(0xbcf16c9cL), tole(0x53c10785L), tole(0x677dcc5fL), tole(0x884da746L), +tole(0x6e0243f4L), tole(0x813228edL), tole(0xb58ee337L), tole(0x5abe882eL), +tole(0xdcf77483L), tole(0x33c71f9aL), tole(0x077bd440L), tole(0xe84bbf59L), +tole(0xce086bd5L), tole(0x213800ccL), tole(0x1584cb16L), tole(0xfab4a00fL), +tole(0x7cfd5ca2L), tole(0x93cd37bbL), tole(0xa771fc61L), tole(0x48419778L), +tole(0xae0e73caL), tole(0x413e18d3L), tole(0x7582d309L), tole(0x9ab2b810L), +tole(0x1cfb44bdL), tole(0xf3cb2fa4L), tole(0xc777e47eL), tole(0x28478f67L), +tole(0x8bf04d66L), tole(0x64c0267fL), tole(0x507ceda5L), tole(0xbf4c86bcL), +tole(0x39057a11L), tole(0xd6351108L), tole(0xe289dad2L), tole(0x0db9b1cbL), +tole(0xebf65579L), tole(0x04c63e60L), tole(0x307af5baL), tole(0xdf4a9ea3L), +tole(0x5903620eL), tole(0xb6330917L), tole(0x828fc2cdL), tole(0x6dbfa9d4L), +tole(0x4bfc7d58L), tole(0xa4cc1641L), tole(0x9070dd9bL), tole(0x7f40b682L), +tole(0xf9094a2fL), tole(0x16392136L), tole(0x2285eaecL), tole(0xcdb581f5L), +tole(0x2bfa6547L), tole(0xc4ca0e5eL), tole(0xf076c584L), tole(0x1f46ae9dL), +tole(0x990f5230L), tole(0x763f3929L), tole(0x4283f2f3L), tole(0xadb399eaL), +tole(0x1c08b7d6L), tole(0xf338dccfL), tole(0xc7841715L), tole(0x28b47c0cL), +tole(0xaefd80a1L), tole(0x41cdebb8L), tole(0x75712062L), tole(0x9a414b7bL), +tole(0x7c0eafc9L), tole(0x933ec4d0L), tole(0xa7820f0aL), tole(0x48b26413L), +tole(0xcefb98beL), tole(0x21cbf3a7L), tole(0x1577387dL), tole(0xfa475364L), +tole(0xdc0487e8L), tole(0x3334ecf1L), tole(0x0788272bL), tole(0xe8b84c32L), +tole(0x6ef1b09fL), tole(0x81c1db86L), tole(0xb57d105cL), tole(0x5a4d7b45L), +tole(0xbc029ff7L), tole(0x5332f4eeL), tole(0x678e3f34L), tole(0x88be542dL), +tole(0x0ef7a880L), tole(0xe1c7c399L), tole(0xd57b0843L), tole(0x3a4b635aL), +tole(0x99fca15bL), tole(0x76ccca42L), tole(0x42700198L), tole(0xad406a81L), +tole(0x2b09962cL), tole(0xc439fd35L), tole(0xf08536efL), tole(0x1fb55df6L), +tole(0xf9fab944L), tole(0x16cad25dL), tole(0x22761987L), tole(0xcd46729eL), +tole(0x4b0f8e33L), tole(0xa43fe52aL), tole(0x90832ef0L), tole(0x7fb345e9L), +tole(0x59f09165L), tole(0xb6c0fa7cL), tole(0x827c31a6L), tole(0x6d4c5abfL), +tole(0xeb05a612L), tole(0x0435cd0bL), tole(0x308906d1L), tole(0xdfb96dc8L), +tole(0x39f6897aL), tole(0xd6c6e263L), tole(0xe27a29b9L), tole(0x0d4a42a0L), +tole(0x8b03be0dL), tole(0x6433d514L), tole(0x508f1eceL), tole(0xbfbf75d7L), +tole(0x120cec3dL), tole(0xfd3c8724L), tole(0xc9804cfeL), tole(0x26b027e7L), +tole(0xa0f9db4aL), tole(0x4fc9b053L), tole(0x7b757b89L), tole(0x94451090L), +tole(0x720af422L), tole(0x9d3a9f3bL), tole(0xa98654e1L), tole(0x46b63ff8L), +tole(0xc0ffc355L), tole(0x2fcfa84cL), tole(0x1b736396L), tole(0xf443088fL), +tole(0xd200dc03L), tole(0x3d30b71aL), tole(0x098c7cc0L), tole(0xe6bc17d9L), +tole(0x60f5eb74L), tole(0x8fc5806dL), tole(0xbb794bb7L), tole(0x544920aeL), +tole(0xb206c41cL), tole(0x5d36af05L), tole(0x698a64dfL), tole(0x86ba0fc6L), +tole(0x00f3f36bL), tole(0xefc39872L), tole(0xdb7f53a8L), tole(0x344f38b1L), +tole(0x97f8fab0L), tole(0x78c891a9L), tole(0x4c745a73L), tole(0xa344316aL), +tole(0x250dcdc7L), tole(0xca3da6deL), tole(0xfe816d04L), tole(0x11b1061dL), +tole(0xf7fee2afL), tole(0x18ce89b6L), tole(0x2c72426cL), tole(0xc3422975L), +tole(0x450bd5d8L), tole(0xaa3bbec1L), tole(0x9e87751bL), tole(0x71b71e02L), +tole(0x57f4ca8eL), tole(0xb8c4a197L), tole(0x8c786a4dL), tole(0x63480154L), +tole(0xe501fdf9L), tole(0x0a3196e0L), tole(0x3e8d5d3aL), tole(0xd1bd3623L), +tole(0x37f2d291L), tole(0xd8c2b988L), tole(0xec7e7252L), tole(0x034e194bL), +tole(0x8507e5e6L), tole(0x6a378effL), tole(0x5e8b4525L), tole(0xb1bb2e3cL)}, +{ +tole(0x00000000L), tole(0x68032cc8L), tole(0xd0065990L), tole(0xb8057558L), +tole(0xa5e0c5d1L), tole(0xcde3e919L), tole(0x75e69c41L), tole(0x1de5b089L), +tole(0x4e2dfd53L), tole(0x262ed19bL), tole(0x9e2ba4c3L), tole(0xf628880bL), +tole(0xebcd3882L), tole(0x83ce144aL), tole(0x3bcb6112L), tole(0x53c84ddaL), +tole(0x9c5bfaa6L), tole(0xf458d66eL), tole(0x4c5da336L), tole(0x245e8ffeL), +tole(0x39bb3f77L), tole(0x51b813bfL), tole(0xe9bd66e7L), tole(0x81be4a2fL), +tole(0xd27607f5L), tole(0xba752b3dL), tole(0x02705e65L), tole(0x6a7372adL), +tole(0x7796c224L), tole(0x1f95eeecL), tole(0xa7909bb4L), tole(0xcf93b77cL), +tole(0x3d5b83bdL), tole(0x5558af75L), tole(0xed5dda2dL), tole(0x855ef6e5L), +tole(0x98bb466cL), tole(0xf0b86aa4L), tole(0x48bd1ffcL), tole(0x20be3334L), +tole(0x73767eeeL), tole(0x1b755226L), tole(0xa370277eL), tole(0xcb730bb6L), +tole(0xd696bb3fL), tole(0xbe9597f7L), tole(0x0690e2afL), tole(0x6e93ce67L), +tole(0xa100791bL), tole(0xc90355d3L), tole(0x7106208bL), tole(0x19050c43L), +tole(0x04e0bccaL), tole(0x6ce39002L), tole(0xd4e6e55aL), tole(0xbce5c992L), +tole(0xef2d8448L), tole(0x872ea880L), tole(0x3f2bddd8L), tole(0x5728f110L), +tole(0x4acd4199L), tole(0x22ce6d51L), tole(0x9acb1809L), tole(0xf2c834c1L), +tole(0x7ab7077aL), tole(0x12b42bb2L), tole(0xaab15eeaL), tole(0xc2b27222L), +tole(0xdf57c2abL), tole(0xb754ee63L), tole(0x0f519b3bL), tole(0x6752b7f3L), +tole(0x349afa29L), tole(0x5c99d6e1L), tole(0xe49ca3b9L), tole(0x8c9f8f71L), +tole(0x917a3ff8L), tole(0xf9791330L), tole(0x417c6668L), tole(0x297f4aa0L), +tole(0xe6ecfddcL), tole(0x8eefd114L), tole(0x36eaa44cL), tole(0x5ee98884L), +tole(0x430c380dL), tole(0x2b0f14c5L), tole(0x930a619dL), tole(0xfb094d55L), +tole(0xa8c1008fL), tole(0xc0c22c47L), tole(0x78c7591fL), tole(0x10c475d7L), +tole(0x0d21c55eL), tole(0x6522e996L), tole(0xdd279cceL), tole(0xb524b006L), +tole(0x47ec84c7L), tole(0x2fefa80fL), tole(0x97eadd57L), tole(0xffe9f19fL), +tole(0xe20c4116L), tole(0x8a0f6ddeL), tole(0x320a1886L), tole(0x5a09344eL), +tole(0x09c17994L), tole(0x61c2555cL), tole(0xd9c72004L), tole(0xb1c40cccL), +tole(0xac21bc45L), tole(0xc422908dL), tole(0x7c27e5d5L), tole(0x1424c91dL), +tole(0xdbb77e61L), tole(0xb3b452a9L), tole(0x0bb127f1L), tole(0x63b20b39L), +tole(0x7e57bbb0L), tole(0x16549778L), tole(0xae51e220L), tole(0xc652cee8L), +tole(0x959a8332L), tole(0xfd99affaL), tole(0x459cdaa2L), tole(0x2d9ff66aL), +tole(0x307a46e3L), tole(0x58796a2bL), tole(0xe07c1f73L), tole(0x887f33bbL), +tole(0xf56e0ef4L), tole(0x9d6d223cL), tole(0x25685764L), tole(0x4d6b7bacL), +tole(0x508ecb25L), tole(0x388de7edL), tole(0x808892b5L), tole(0xe88bbe7dL), +tole(0xbb43f3a7L), tole(0xd340df6fL), tole(0x6b45aa37L), tole(0x034686ffL), +tole(0x1ea33676L), tole(0x76a01abeL), tole(0xcea56fe6L), tole(0xa6a6432eL), +tole(0x6935f452L), tole(0x0136d89aL), tole(0xb933adc2L), tole(0xd130810aL), +tole(0xccd53183L), tole(0xa4d61d4bL), tole(0x1cd36813L), tole(0x74d044dbL), +tole(0x27180901L), tole(0x4f1b25c9L), tole(0xf71e5091L), tole(0x9f1d7c59L), +tole(0x82f8ccd0L), tole(0xeafbe018L), tole(0x52fe9540L), tole(0x3afdb988L), +tole(0xc8358d49L), tole(0xa036a181L), tole(0x1833d4d9L), tole(0x7030f811L), +tole(0x6dd54898L), tole(0x05d66450L), tole(0xbdd31108L), tole(0xd5d03dc0L), +tole(0x8618701aL), tole(0xee1b5cd2L), tole(0x561e298aL), tole(0x3e1d0542L), +tole(0x23f8b5cbL), tole(0x4bfb9903L), tole(0xf3feec5bL), tole(0x9bfdc093L), +tole(0x546e77efL), tole(0x3c6d5b27L), tole(0x84682e7fL), tole(0xec6b02b7L), +tole(0xf18eb23eL), tole(0x998d9ef6L), tole(0x2188ebaeL), tole(0x498bc766L), +tole(0x1a438abcL), tole(0x7240a674L), tole(0xca45d32cL), tole(0xa246ffe4L), +tole(0xbfa34f6dL), tole(0xd7a063a5L), tole(0x6fa516fdL), tole(0x07a63a35L), +tole(0x8fd9098eL), tole(0xe7da2546L), tole(0x5fdf501eL), tole(0x37dc7cd6L), +tole(0x2a39cc5fL), tole(0x423ae097L), tole(0xfa3f95cfL), tole(0x923cb907L), +tole(0xc1f4f4ddL), tole(0xa9f7d815L), tole(0x11f2ad4dL), tole(0x79f18185L), +tole(0x6414310cL), tole(0x0c171dc4L), tole(0xb412689cL), tole(0xdc114454L), +tole(0x1382f328L), tole(0x7b81dfe0L), tole(0xc384aab8L), tole(0xab878670L), +tole(0xb66236f9L), tole(0xde611a31L), tole(0x66646f69L), tole(0x0e6743a1L), +tole(0x5daf0e7bL), tole(0x35ac22b3L), tole(0x8da957ebL), tole(0xe5aa7b23L), +tole(0xf84fcbaaL), tole(0x904ce762L), tole(0x2849923aL), tole(0x404abef2L), +tole(0xb2828a33L), tole(0xda81a6fbL), tole(0x6284d3a3L), tole(0x0a87ff6bL), +tole(0x17624fe2L), tole(0x7f61632aL), tole(0xc7641672L), tole(0xaf673abaL), +tole(0xfcaf7760L), tole(0x94ac5ba8L), tole(0x2ca92ef0L), tole(0x44aa0238L), +tole(0x594fb2b1L), tole(0x314c9e79L), tole(0x8949eb21L), tole(0xe14ac7e9L), +tole(0x2ed97095L), tole(0x46da5c5dL), tole(0xfedf2905L), tole(0x96dc05cdL), +tole(0x8b39b544L), tole(0xe33a998cL), tole(0x5b3fecd4L), tole(0x333cc01cL), +tole(0x60f48dc6L), tole(0x08f7a10eL), tole(0xb0f2d456L), tole(0xd8f1f89eL), +tole(0xc5144817L), tole(0xad1764dfL), tole(0x15121187L), tole(0x7d113d4fL)}, +{ +tole(0x00000000L), tole(0x493c7d27L), tole(0x9278fa4eL), tole(0xdb448769L), +tole(0x211d826dL), tole(0x6821ff4aL), tole(0xb3657823L), tole(0xfa590504L), +tole(0x423b04daL), tole(0x0b0779fdL), tole(0xd043fe94L), tole(0x997f83b3L), +tole(0x632686b7L), tole(0x2a1afb90L), tole(0xf15e7cf9L), tole(0xb86201deL), +tole(0x847609b4L), tole(0xcd4a7493L), tole(0x160ef3faL), tole(0x5f328eddL), +tole(0xa56b8bd9L), tole(0xec57f6feL), tole(0x37137197L), tole(0x7e2f0cb0L), +tole(0xc64d0d6eL), tole(0x8f717049L), tole(0x5435f720L), tole(0x1d098a07L), +tole(0xe7508f03L), tole(0xae6cf224L), tole(0x7528754dL), tole(0x3c14086aL), +tole(0x0d006599L), tole(0x443c18beL), tole(0x9f789fd7L), tole(0xd644e2f0L), +tole(0x2c1de7f4L), tole(0x65219ad3L), tole(0xbe651dbaL), tole(0xf759609dL), +tole(0x4f3b6143L), tole(0x06071c64L), tole(0xdd439b0dL), tole(0x947fe62aL), +tole(0x6e26e32eL), tole(0x271a9e09L), tole(0xfc5e1960L), tole(0xb5626447L), +tole(0x89766c2dL), tole(0xc04a110aL), tole(0x1b0e9663L), tole(0x5232eb44L), +tole(0xa86bee40L), tole(0xe1579367L), tole(0x3a13140eL), tole(0x732f6929L), +tole(0xcb4d68f7L), tole(0x827115d0L), tole(0x593592b9L), tole(0x1009ef9eL), +tole(0xea50ea9aL), tole(0xa36c97bdL), tole(0x782810d4L), tole(0x31146df3L), +tole(0x1a00cb32L), tole(0x533cb615L), tole(0x8878317cL), tole(0xc1444c5bL), +tole(0x3b1d495fL), tole(0x72213478L), tole(0xa965b311L), tole(0xe059ce36L), +tole(0x583bcfe8L), tole(0x1107b2cfL), tole(0xca4335a6L), tole(0x837f4881L), +tole(0x79264d85L), tole(0x301a30a2L), tole(0xeb5eb7cbL), tole(0xa262caecL), +tole(0x9e76c286L), tole(0xd74abfa1L), tole(0x0c0e38c8L), tole(0x453245efL), +tole(0xbf6b40ebL), tole(0xf6573dccL), tole(0x2d13baa5L), tole(0x642fc782L), +tole(0xdc4dc65cL), tole(0x9571bb7bL), tole(0x4e353c12L), tole(0x07094135L), +tole(0xfd504431L), tole(0xb46c3916L), tole(0x6f28be7fL), tole(0x2614c358L), +tole(0x1700aeabL), tole(0x5e3cd38cL), tole(0x857854e5L), tole(0xcc4429c2L), +tole(0x361d2cc6L), tole(0x7f2151e1L), tole(0xa465d688L), tole(0xed59abafL), +tole(0x553baa71L), tole(0x1c07d756L), tole(0xc743503fL), tole(0x8e7f2d18L), +tole(0x7426281cL), tole(0x3d1a553bL), tole(0xe65ed252L), tole(0xaf62af75L), +tole(0x9376a71fL), tole(0xda4ada38L), tole(0x010e5d51L), tole(0x48322076L), +tole(0xb26b2572L), tole(0xfb575855L), tole(0x2013df3cL), tole(0x692fa21bL), +tole(0xd14da3c5L), tole(0x9871dee2L), tole(0x4335598bL), tole(0x0a0924acL), +tole(0xf05021a8L), tole(0xb96c5c8fL), tole(0x6228dbe6L), tole(0x2b14a6c1L), +tole(0x34019664L), tole(0x7d3deb43L), tole(0xa6796c2aL), tole(0xef45110dL), +tole(0x151c1409L), tole(0x5c20692eL), tole(0x8764ee47L), tole(0xce589360L), +tole(0x763a92beL), tole(0x3f06ef99L), tole(0xe44268f0L), tole(0xad7e15d7L), +tole(0x572710d3L), tole(0x1e1b6df4L), tole(0xc55fea9dL), tole(0x8c6397baL), +tole(0xb0779fd0L), tole(0xf94be2f7L), tole(0x220f659eL), tole(0x6b3318b9L), +tole(0x916a1dbdL), tole(0xd856609aL), tole(0x0312e7f3L), tole(0x4a2e9ad4L), +tole(0xf24c9b0aL), tole(0xbb70e62dL), tole(0x60346144L), tole(0x29081c63L), +tole(0xd3511967L), tole(0x9a6d6440L), tole(0x4129e329L), tole(0x08159e0eL), +tole(0x3901f3fdL), tole(0x703d8edaL), tole(0xab7909b3L), tole(0xe2457494L), +tole(0x181c7190L), tole(0x51200cb7L), tole(0x8a648bdeL), tole(0xc358f6f9L), +tole(0x7b3af727L), tole(0x32068a00L), tole(0xe9420d69L), tole(0xa07e704eL), +tole(0x5a27754aL), tole(0x131b086dL), tole(0xc85f8f04L), tole(0x8163f223L), +tole(0xbd77fa49L), tole(0xf44b876eL), tole(0x2f0f0007L), tole(0x66337d20L), +tole(0x9c6a7824L), tole(0xd5560503L), tole(0x0e12826aL), tole(0x472eff4dL), +tole(0xff4cfe93L), tole(0xb67083b4L), tole(0x6d3404ddL), tole(0x240879faL), +tole(0xde517cfeL), tole(0x976d01d9L), tole(0x4c2986b0L), tole(0x0515fb97L), +tole(0x2e015d56L), tole(0x673d2071L), tole(0xbc79a718L), tole(0xf545da3fL), +tole(0x0f1cdf3bL), tole(0x4620a21cL), tole(0x9d642575L), tole(0xd4585852L), +tole(0x6c3a598cL), tole(0x250624abL), tole(0xfe42a3c2L), tole(0xb77edee5L), +tole(0x4d27dbe1L), tole(0x041ba6c6L), tole(0xdf5f21afL), tole(0x96635c88L), +tole(0xaa7754e2L), tole(0xe34b29c5L), tole(0x380faeacL), tole(0x7133d38bL), +tole(0x8b6ad68fL), tole(0xc256aba8L), tole(0x19122cc1L), tole(0x502e51e6L), +tole(0xe84c5038L), tole(0xa1702d1fL), tole(0x7a34aa76L), tole(0x3308d751L), +tole(0xc951d255L), tole(0x806daf72L), tole(0x5b29281bL), tole(0x1215553cL), +tole(0x230138cfL), tole(0x6a3d45e8L), tole(0xb179c281L), tole(0xf845bfa6L), +tole(0x021cbaa2L), tole(0x4b20c785L), tole(0x906440ecL), tole(0xd9583dcbL), +tole(0x613a3c15L), tole(0x28064132L), tole(0xf342c65bL), tole(0xba7ebb7cL), +tole(0x4027be78L), tole(0x091bc35fL), tole(0xd25f4436L), tole(0x9b633911L), +tole(0xa777317bL), tole(0xee4b4c5cL), tole(0x350fcb35L), tole(0x7c33b612L), +tole(0x866ab316L), tole(0xcf56ce31L), tole(0x14124958L), tole(0x5d2e347fL), +tole(0xe54c35a1L), tole(0xac704886L), tole(0x7734cfefL), tole(0x3e08b2c8L), +tole(0xc451b7ccL), tole(0x8d6dcaebL), tole(0x56294d82L), tole(0x1f1530a5L)}, +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/csum.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/csum.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,1020 @@ +/* + * csum.c --- checksumming of ext3 structures + * + * Copyright (C) 2006 Cluster File Systems, Inc. + * Copyright (C) 2006, 2007 by Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "crc16.h" +#include + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#ifdef DEBUG +#define STATIC +#else +#define STATIC static +#endif + +void ext2fs_init_csum_seed(ext2_filsys fs) +{ + if (ext2fs_has_feature_csum_seed(fs->super)) + fs->csum_seed = fs->super->s_checksum_seed; + else if (ext2fs_has_feature_metadata_csum(fs->super) || + ext2fs_has_feature_ea_inode(fs->super)) + fs->csum_seed = ext2fs_crc32c_le(~0, fs->super->s_uuid, + sizeof(fs->super->s_uuid)); +} + +static __u32 ext2fs_mmp_csum(ext2_filsys fs, struct mmp_struct *mmp) +{ + int offset = offsetof(struct mmp_struct, mmp_checksum); + + return ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)mmp, offset); +} + +int ext2fs_mmp_csum_verify(ext2_filsys fs, struct mmp_struct *mmp) +{ + __u32 calculated; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + + calculated = ext2fs_mmp_csum(fs, mmp); + + return ext2fs_le32_to_cpu(mmp->mmp_checksum) == calculated; +} + +errcode_t ext2fs_mmp_csum_set(ext2_filsys fs, struct mmp_struct *mmp) +{ + __u32 crc; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + crc = ext2fs_mmp_csum(fs, mmp); + mmp->mmp_checksum = ext2fs_cpu_to_le32(crc); + + return 0; +} + +int ext2fs_verify_csum_type(ext2_filsys fs, struct ext2_super_block *sb) +{ + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + + return sb->s_checksum_type == EXT2_CRC32C_CHKSUM; +} + +static __u32 ext2fs_superblock_csum(ext2_filsys fs EXT2FS_ATTR((unused)), + struct ext2_super_block *sb) +{ + int offset = offsetof(struct ext2_super_block, s_checksum); + + return ext2fs_crc32c_le(~0, (unsigned char *)sb, offset); +} + +/* NOTE: The input to this function MUST be in LE order */ +int ext2fs_superblock_csum_verify(ext2_filsys fs, struct ext2_super_block *sb) +{ + __u32 flag, calculated; + + if (fs->flags & EXT2_FLAG_SWAP_BYTES) + flag = EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; + else + flag = ext2fs_cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); + + if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, flag)) + return 1; + + calculated = ext2fs_superblock_csum(fs, sb); + + return ext2fs_le32_to_cpu(sb->s_checksum) == calculated; +} + +/* NOTE: The input to this function MUST be in LE order */ +errcode_t ext2fs_superblock_csum_set(ext2_filsys fs, + struct ext2_super_block *sb) +{ + __u32 flag, crc; + + if (fs->flags & EXT2_FLAG_SWAP_BYTES) + flag = EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; + else + flag = ext2fs_cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); + + if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, flag)) + return 0; + + crc = ext2fs_superblock_csum(fs, sb); + sb->s_checksum = ext2fs_cpu_to_le32(crc); + + return 0; +} + +static errcode_t ext2fs_ext_attr_block_csum(ext2_filsys fs, + ext2_ino_t inum EXT2FS_ATTR((unused)), + blk64_t block, + struct ext2_ext_attr_header *hdr, + __u32 *crc) +{ + char *buf = (char *)hdr; + __u32 old_crc = hdr->h_checksum; + + hdr->h_checksum = 0; + block = ext2fs_cpu_to_le64(block); + *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&block, + sizeof(block)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, fs->blocksize); + hdr->h_checksum = old_crc; + + return 0; +} + +int ext2fs_ext_attr_block_csum_verify(ext2_filsys fs, ext2_ino_t inum, + blk64_t block, + struct ext2_ext_attr_header *hdr) +{ + __u32 calculated; + errcode_t retval; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + + retval = ext2fs_ext_attr_block_csum(fs, inum, block, hdr, &calculated); + if (retval) + return 0; + + return ext2fs_le32_to_cpu(hdr->h_checksum) == calculated; +} + +errcode_t ext2fs_ext_attr_block_csum_set(ext2_filsys fs, ext2_ino_t inum, + blk64_t block, + struct ext2_ext_attr_header *hdr) +{ + errcode_t retval; + __u32 crc; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + retval = ext2fs_ext_attr_block_csum(fs, inum, block, hdr, &crc); + if (retval) + return retval; + hdr->h_checksum = ext2fs_cpu_to_le32(crc); + return 0; +} + +static __u16 do_nothing16(__u16 x) +{ + return x; +} + +static __u16 disk_to_host16(__u16 x) +{ + return ext2fs_le16_to_cpu(x); +} + +static errcode_t __get_dx_countlimit(ext2_filsys fs, + struct ext2_dir_entry *dirent, + struct ext2_dx_countlimit **cc, + int *offset, + int need_swab) +{ + struct ext2_dir_entry *dp; + struct ext2_dx_root_info *root; + struct ext2_dx_countlimit *c; + int count_offset, max_sane_entries; + unsigned int rec_len; + __u16 (*translate)(__u16) = (need_swab ? disk_to_host16 : do_nothing16); + + rec_len = translate(dirent->rec_len); + + if (rec_len == fs->blocksize && translate(dirent->name_len) == 0) + count_offset = 8; + else if (rec_len == 12) { + dp = (struct ext2_dir_entry *)(((char *)dirent) + rec_len); + rec_len = translate(dp->rec_len); + if (rec_len != fs->blocksize - 12) + return EXT2_ET_DB_NOT_FOUND; + root = (struct ext2_dx_root_info *)(((char *)dp + 12)); + if (root->reserved_zero || + root->info_length != sizeof(struct ext2_dx_root_info)) + return EXT2_ET_DB_NOT_FOUND; + count_offset = 32; + } else + return EXT2_ET_DB_NOT_FOUND; + + c = (struct ext2_dx_countlimit *)(((char *)dirent) + count_offset); + max_sane_entries = (fs->blocksize - count_offset) / + sizeof(struct ext2_dx_entry); + if (ext2fs_le16_to_cpu(c->limit) > max_sane_entries || + ext2fs_le16_to_cpu(c->count) > max_sane_entries) + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; + + if (offset) + *offset = count_offset; + if (cc) + *cc = c; + + return 0; +} + +errcode_t ext2fs_get_dx_countlimit(ext2_filsys fs, + struct ext2_dir_entry *dirent, + struct ext2_dx_countlimit **cc, + int *offset) +{ + return __get_dx_countlimit(fs, dirent, cc, offset, 0); +} + +void ext2fs_initialize_dirent_tail(ext2_filsys fs, + struct ext2_dir_entry_tail *t) +{ + memset(t, 0, sizeof(struct ext2_dir_entry_tail)); + ext2fs_set_rec_len(fs, sizeof(struct ext2_dir_entry_tail), + (struct ext2_dir_entry *)t); + t->det_reserved_name_len = EXT2_DIR_NAME_LEN_CSUM; +} + +static errcode_t __get_dirent_tail(ext2_filsys fs, + struct ext2_dir_entry *dirent, + struct ext2_dir_entry_tail **tt, + int need_swab) +{ + struct ext2_dir_entry *d; + void *top; + struct ext2_dir_entry_tail *t; + unsigned int rec_len; + errcode_t retval = 0; + __u16 (*translate)(__u16) = (need_swab ? disk_to_host16 : do_nothing16); + + d = dirent; + top = EXT2_DIRENT_TAIL(dirent, fs->blocksize); + + rec_len = translate(d->rec_len); + while (rec_len && !(rec_len & 0x3)) { + d = (struct ext2_dir_entry *)(((char *)d) + rec_len); + if ((void *)d >= top) + break; + rec_len = translate(d->rec_len); + } + + if (d != top) + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; + + t = (struct ext2_dir_entry_tail *)d; + if (t->det_reserved_zero1 || + translate(t->det_rec_len) != sizeof(struct ext2_dir_entry_tail) || + translate(t->det_reserved_name_len) != EXT2_DIR_NAME_LEN_CSUM) + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; + + if (tt) + *tt = t; + return retval; +} + +int ext2fs_dirent_has_tail(ext2_filsys fs, struct ext2_dir_entry *dirent) +{ + return __get_dirent_tail(fs, dirent, NULL, 0) == 0; +} + +static errcode_t ext2fs_dirent_csum(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent, __u32 *crc, + int size) +{ + errcode_t retval; + char *buf = (char *)dirent; + __u32 gen; + struct ext2_inode inode; + + retval = ext2fs_read_inode(fs, inum, &inode); + if (retval) + return retval; + + inum = ext2fs_cpu_to_le32(inum); + gen = ext2fs_cpu_to_le32(inode.i_generation); + *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum, + sizeof(inum)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, size); + + return 0; +} + +int ext2fs_dirent_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + errcode_t retval; + __u32 calculated; + struct ext2_dir_entry_tail *t; + + retval = __get_dirent_tail(fs, dirent, &t, 1); + if (retval) + return 1; + + /* + * The checksum field is overlaid with the dirent->name field + * so the swapfs.c functions won't change the endianness. + */ + retval = ext2fs_dirent_csum(fs, inum, dirent, &calculated, + (char *)t - (char *)dirent); + if (retval) + return 0; + return ext2fs_le32_to_cpu(t->det_checksum) == calculated; +} + +static errcode_t ext2fs_dirent_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + errcode_t retval; + __u32 crc; + struct ext2_dir_entry_tail *t; + + retval = __get_dirent_tail(fs, dirent, &t, 1); + if (retval) + return retval; + + /* swapfs.c functions don't change the checksum endianness */ + retval = ext2fs_dirent_csum(fs, inum, dirent, &crc, + (char *)t - (char *)dirent); + if (retval) + return retval; + t->det_checksum = ext2fs_cpu_to_le32(crc); + return 0; +} + +static errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent, + __u32 *crc, int count_offset, int count, + struct ext2_dx_tail *t) +{ + errcode_t retval; + char *buf = (char *)dirent; + int size; + __u32 old_csum, gen; + struct ext2_inode inode; + + size = count_offset + (count * sizeof(struct ext2_dx_entry)); + old_csum = t->dt_checksum; + t->dt_checksum = 0; + + retval = ext2fs_read_inode(fs, inum, &inode); + if (retval) + return retval; + + inum = ext2fs_cpu_to_le32(inum); + gen = ext2fs_cpu_to_le32(inode.i_generation); + *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum, + sizeof(inum)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, size); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)t, + sizeof(struct ext2_dx_tail)); + t->dt_checksum = old_csum; + + return 0; +} + +static int ext2fs_dx_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + __u32 calculated; + errcode_t retval; + struct ext2_dx_countlimit *c; + struct ext2_dx_tail *t; + int count_offset, limit, count; + + retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1); + if (retval) + return 1; + limit = ext2fs_le16_to_cpu(c->limit); + count = ext2fs_le16_to_cpu(c->count); + if (count_offset + (limit * sizeof(struct ext2_dx_entry)) > + fs->blocksize - sizeof(struct ext2_dx_tail)) + return 0; + /* htree structs are accessed in LE order */ + t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit); + retval = ext2fs_dx_csum(fs, inum, dirent, &calculated, count_offset, + count, t); + if (retval) + return 0; + + return ext2fs_le32_to_cpu(t->dt_checksum) == calculated; +} + +static errcode_t ext2fs_dx_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + __u32 crc; + errcode_t retval = 0; + struct ext2_dx_countlimit *c; + struct ext2_dx_tail *t; + int count_offset, limit, count; + + retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1); + if (retval) + return retval; + limit = ext2fs_le16_to_cpu(c->limit); + count = ext2fs_le16_to_cpu(c->count); + if (count_offset + (limit * sizeof(struct ext2_dx_entry)) > + fs->blocksize - sizeof(struct ext2_dx_tail)) + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; + t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit); + + /* htree structs are accessed in LE order */ + retval = ext2fs_dx_csum(fs, inum, dirent, &crc, count_offset, count, t); + if (retval) + return retval; + t->dt_checksum = ext2fs_cpu_to_le32(crc); + return retval; +} + +int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + + if (__get_dirent_tail(fs, dirent, NULL, 1) == 0) + return ext2fs_dirent_csum_verify(fs, inum, dirent); + if (__get_dx_countlimit(fs, dirent, NULL, NULL, 1) == 0) + return ext2fs_dx_csum_verify(fs, inum, dirent); + + return 0; +} + +errcode_t ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + if (__get_dirent_tail(fs, dirent, NULL, 1) == 0) + return ext2fs_dirent_csum_set(fs, inum, dirent); + if (__get_dx_countlimit(fs, dirent, NULL, NULL, 1) == 0) + return ext2fs_dx_csum_set(fs, inum, dirent); + + if (fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) + return 0; + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; +} + +#define EXT3_EXTENT_TAIL_OFFSET(hdr) (sizeof(struct ext3_extent_header) + \ + (sizeof(struct ext3_extent) * ext2fs_le16_to_cpu((hdr)->eh_max))) + +static struct ext3_extent_tail *get_extent_tail(struct ext3_extent_header *h) +{ + return (struct ext3_extent_tail *)(((char *)h) + + EXT3_EXTENT_TAIL_OFFSET(h)); +} + +static errcode_t ext2fs_extent_block_csum(ext2_filsys fs, ext2_ino_t inum, + struct ext3_extent_header *eh, + __u32 *crc) +{ + int size; + __u32 gen; + errcode_t retval; + struct ext2_inode inode; + + size = EXT3_EXTENT_TAIL_OFFSET(eh) + offsetof(struct ext3_extent_tail, + et_checksum); + + retval = ext2fs_read_inode(fs, inum, &inode); + if (retval) + return retval; + inum = ext2fs_cpu_to_le32(inum); + gen = ext2fs_cpu_to_le32(inode.i_generation); + *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum, + sizeof(inum)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)eh, size); + + return 0; +} + +int ext2fs_extent_block_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext3_extent_header *eh) +{ + errcode_t retval; + __u32 provided, calculated; + struct ext3_extent_tail *t = get_extent_tail(eh); + + /* + * The extent tree structures are accessed in LE order, so we must + * swap the checksum bytes here. + */ + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + + provided = ext2fs_le32_to_cpu(t->et_checksum); + retval = ext2fs_extent_block_csum(fs, inum, eh, &calculated); + if (retval) + return 0; + + return provided == calculated; +} + +errcode_t ext2fs_extent_block_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext3_extent_header *eh) +{ + errcode_t retval; + __u32 crc; + struct ext3_extent_tail *t = get_extent_tail(eh); + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + /* + * The extent tree structures are accessed in LE order, so we must + * swap the checksum bytes here. + */ + retval = ext2fs_extent_block_csum(fs, inum, eh, &crc); + if (retval) + return retval; + t->et_checksum = ext2fs_cpu_to_le32(crc); + return retval; +} + +int ext2fs_inode_bitmap_csum_verify(ext2_filsys fs, dgrp_t group, + char *bitmap, int size) +{ + struct ext4_group_desc *gdp = (struct ext4_group_desc *) + ext2fs_group_desc(fs, fs->group_desc, group); + __u32 provided, calculated; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + provided = gdp->bg_inode_bitmap_csum_lo; + calculated = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, + size); + if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) + provided |= (__u32)gdp->bg_inode_bitmap_csum_hi << 16; + else + calculated &= 0xFFFF; + + return provided == calculated; +} + +errcode_t ext2fs_inode_bitmap_csum_set(ext2_filsys fs, dgrp_t group, + char *bitmap, int size) +{ + __u32 crc; + struct ext4_group_desc *gdp = (struct ext4_group_desc *) + ext2fs_group_desc(fs, fs->group_desc, group); + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, size); + gdp->bg_inode_bitmap_csum_lo = crc & 0xFFFF; + if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) + gdp->bg_inode_bitmap_csum_hi = crc >> 16; + + return 0; +} + +int ext2fs_block_bitmap_csum_verify(ext2_filsys fs, dgrp_t group, + char *bitmap, int size) +{ + struct ext4_group_desc *gdp = (struct ext4_group_desc *) + ext2fs_group_desc(fs, fs->group_desc, group); + __u32 provided, calculated; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + provided = gdp->bg_block_bitmap_csum_lo; + calculated = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, + size); + if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) + provided |= (__u32)gdp->bg_block_bitmap_csum_hi << 16; + else + calculated &= 0xFFFF; + + return provided == calculated; +} + +errcode_t ext2fs_block_bitmap_csum_set(ext2_filsys fs, dgrp_t group, + char *bitmap, int size) +{ + __u32 crc; + struct ext4_group_desc *gdp = (struct ext4_group_desc *) + ext2fs_group_desc(fs, fs->group_desc, group); + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, size); + gdp->bg_block_bitmap_csum_lo = crc & 0xFFFF; + if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) + gdp->bg_block_bitmap_csum_hi = crc >> 16; + + return 0; +} + +static errcode_t ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum, + struct ext2_inode_large *inode, + __u32 *crc, int has_hi) +{ + __u32 gen; + struct ext2_inode_large *desc = inode; + size_t size = EXT2_INODE_SIZE(fs->super); + __u16 old_lo; + __u16 old_hi = 0; + + old_lo = inode->i_checksum_lo; + inode->i_checksum_lo = 0; + if (has_hi) { + old_hi = inode->i_checksum_hi; + inode->i_checksum_hi = 0; + } + + inum = ext2fs_cpu_to_le32(inum); + gen = inode->i_generation; + *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum, + sizeof(inum)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)desc, size); + + inode->i_checksum_lo = old_lo; + if (has_hi) + inode->i_checksum_hi = old_hi; + return 0; +} + +int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_inode_large *inode) +{ + errcode_t retval; + __u32 provided, calculated; + unsigned int i, has_hi; + char *cp; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + + has_hi = (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE && + inode->i_extra_isize >= EXT4_INODE_CSUM_HI_EXTRA_END); + + provided = ext2fs_le16_to_cpu(inode->i_checksum_lo); + retval = ext2fs_inode_csum(fs, inum, inode, &calculated, has_hi); + if (retval) + return 0; + if (has_hi) { + __u32 hi = ext2fs_le16_to_cpu(inode->i_checksum_hi); + provided |= hi << 16; + } else + calculated &= 0xFFFF; + + if (provided == calculated) + return 1; + + /* + * If the checksum didn't match, it's possible it was due to + * the inode being all zero's. It's unlikely this is the + * case, but it can happen. So check for it here. (We only + * check the base inode since that's good enough, and it's not + * worth the bother to figure out how much of the extended + * inode, if any, is present.) + */ + for (cp = (char *) inode, i = 0; + i < sizeof(struct ext2_inode); + cp++, i++) + if (*cp) + return 0; + return 1; /* Inode must have been all zero's */ +} + +errcode_t ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_inode_large *inode) +{ + errcode_t retval; + __u32 crc; + int has_hi; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + has_hi = (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE && + inode->i_extra_isize >= EXT4_INODE_CSUM_HI_EXTRA_END); + + retval = ext2fs_inode_csum(fs, inum, inode, &crc, has_hi); + if (retval) + return retval; + inode->i_checksum_lo = ext2fs_cpu_to_le16(crc & 0xFFFF); + if (has_hi) + inode->i_checksum_hi = ext2fs_cpu_to_le16(crc >> 16); + return 0; +} + +__u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group) +{ + struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc, + group); + size_t offset, size = EXT2_DESC_SIZE(fs->super); + __u16 crc = 0; +#ifdef WORDS_BIGENDIAN + struct ext4_group_desc swabdesc; + size_t save_size = size; + const size_t ext4_bg_size = sizeof(struct ext4_group_desc); + struct ext2_group_desc *save_desc = desc; + + /* Have to swab back to little-endian to do the checksum */ + if (size > ext4_bg_size) + size = ext4_bg_size; + memcpy(&swabdesc, desc, size); + ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc); + desc = (struct ext2_group_desc *) &swabdesc; + group = ext2fs_swab32(group); +#endif + + if (ext2fs_has_feature_metadata_csum(fs->super)) { + /* new metadata csum code */ + __u16 old_crc; + __u32 crc32; + + old_crc = desc->bg_checksum; + desc->bg_checksum = 0; + crc32 = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&group, + sizeof(group)); + crc32 = ext2fs_crc32c_le(crc32, (unsigned char *)desc, + size); + desc->bg_checksum = old_crc; +#ifdef WORDS_BIGENDIAN + if (save_size > ext4_bg_size) + crc32 = ext2fs_crc32c_le(crc32, + (unsigned char *)save_desc + ext4_bg_size, + save_size - ext4_bg_size); +#endif + crc = crc32 & 0xFFFF; + goto out; + } + + /* old crc16 code */ + offset = offsetof(struct ext2_group_desc, bg_checksum); + crc = ext2fs_crc16(~0, fs->super->s_uuid, + sizeof(fs->super->s_uuid)); + crc = ext2fs_crc16(crc, &group, sizeof(group)); + crc = ext2fs_crc16(crc, desc, offset); + offset += sizeof(desc->bg_checksum); /* skip checksum */ + /* for checksum of struct ext4_group_desc do the rest...*/ + if (offset < size) { + crc = ext2fs_crc16(crc, (char *)desc + offset, + size - offset); + } +#ifdef WORDS_BIGENDIAN + /* + * If the size of the bg descriptor is greater than 64 + * bytes, which is the size of the traditional ext4 bg + * descriptor, checksum the rest of the descriptor here + */ + if (save_size > ext4_bg_size) + crc = ext2fs_crc16(crc, (char *)save_desc + ext4_bg_size, + save_size - ext4_bg_size); +#endif + +out: + return crc; +} + +int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group) +{ + if (ext2fs_has_group_desc_csum(fs) && + (ext2fs_bg_checksum(fs, group) != + ext2fs_group_desc_csum(fs, group))) + return 0; + + return 1; +} + +void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group) +{ + if (!ext2fs_has_group_desc_csum(fs)) + return; + + /* ext2fs_bg_checksum_set() sets the actual checksum field but + * does not calculate the checksum itself. */ + ext2fs_bg_checksum_set(fs, group, ext2fs_group_desc_csum(fs, group)); +} + +static __u32 find_last_inode_ingrp(ext2fs_inode_bitmap bitmap, + __u32 inodes_per_grp, dgrp_t grp_no) +{ + ext2_ino_t i, start_ino, end_ino; + + start_ino = grp_no * inodes_per_grp + 1; + end_ino = start_ino + inodes_per_grp - 1; + + for (i = end_ino; i >= start_ino; i--) { + if (ext2fs_fast_test_inode_bitmap2(bitmap, i)) + return i - start_ino + 1; + } + return inodes_per_grp; +} + +/* update the bitmap flags, set the itable high watermark, and calculate + * checksums for the group descriptors */ +errcode_t ext2fs_set_gdt_csum(ext2_filsys fs) +{ + struct ext2_super_block *sb = fs->super; + int dirty = 0; + dgrp_t i; + + if (!fs->inode_map) + return EXT2_ET_NO_INODE_BITMAP; + + if (!ext2fs_has_group_desc_csum(fs)) + return 0; + + for (i = 0; i < fs->group_desc_count; i++) { + __u32 old_csum = ext2fs_bg_checksum(fs, i); + __u32 old_unused = ext2fs_bg_itable_unused(fs, i); + __u32 old_flags = ext2fs_bg_flags(fs, i); + __u32 old_free_inodes_count = ext2fs_bg_free_inodes_count(fs, i); + __u32 old_free_blocks_count = ext2fs_bg_free_blocks_count(fs, i); + + if (old_free_blocks_count == sb->s_blocks_per_group && + i != fs->group_desc_count - 1) + ext2fs_bg_flags_set(fs, i, EXT2_BG_BLOCK_UNINIT); + + if (old_free_inodes_count == sb->s_inodes_per_group) { + ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT); + ext2fs_bg_itable_unused_set(fs, i, sb->s_inodes_per_group); + } else { + int unused = + sb->s_inodes_per_group - + find_last_inode_ingrp(fs->inode_map, + sb->s_inodes_per_group, i); + + ext2fs_bg_flags_clear(fs, i, EXT2_BG_INODE_UNINIT); + ext2fs_bg_itable_unused_set(fs, i, unused); + } + + ext2fs_group_desc_csum_set(fs, i); + if (old_flags != ext2fs_bg_flags(fs, i)) + dirty = 1; + if (old_unused != ext2fs_bg_itable_unused(fs, i)) + dirty = 1; + if (old_csum != ext2fs_bg_checksum(fs, i)) + dirty = 1; + } + if (dirty) + ext2fs_mark_super_dirty(fs); + return 0; +} + +#ifdef DEBUG +#include "e2p/e2p.h" + +void print_csum(const char *msg, ext2_filsys fs, dgrp_t group) +{ + __u16 crc1, crc2, crc3; + dgrp_t swabgroup; + struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc, + group); + size_t size = EXT2_DESC_SIZE(fs->super); + struct ext2_super_block *sb = fs->super; + int offset = offsetof(struct ext2_group_desc, bg_checksum); +#ifdef WORDS_BIGENDIAN + struct ext4_group_desc swabdesc; + struct ext2_group_desc *save_desc = desc; + const size_t ext4_bg_size = sizeof(struct ext4_group_desc); + size_t save_size = size; +#endif + +#ifdef WORDS_BIGENDIAN + /* Have to swab back to little-endian to do the checksum */ + if (size > ext4_bg_size) + size = ext4_bg_size; + memcpy(&swabdesc, desc, size); + ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc); + desc = (struct ext2_group_desc *) &swabdesc; + + swabgroup = ext2fs_swab32(group); +#else + swabgroup = group; +#endif + + crc1 = ext2fs_crc16(~0, sb->s_uuid, sizeof(fs->super->s_uuid)); + crc2 = ext2fs_crc16(crc1, &swabgroup, sizeof(swabgroup)); + crc3 = ext2fs_crc16(crc2, desc, offset); + offset += sizeof(desc->bg_checksum); /* skip checksum */ + /* for checksum of struct ext4_group_desc do the rest...*/ + if (offset < size) + crc3 = ext2fs_crc16(crc3, (char *)desc + offset, size - offset); +#ifdef WORDS_BIGENDIAN + if (save_size > ext4_bg_size) + crc3 = ext2fs_crc16(crc3, (char *)save_desc + ext4_bg_size, + save_size - ext4_bg_size); +#endif + + printf("%s UUID %s=%04x, grp %u=%04x: %04x=%04x\n", + msg, e2p_uuid2str(sb->s_uuid), crc1, group, crc2, crc3, + ext2fs_group_desc_csum(fs, group)); +} + +unsigned char sb_uuid[16] = { 0x4f, 0x25, 0xe8, 0xcf, 0xe7, 0x97, 0x48, 0x23, + 0xbe, 0xfa, 0xa7, 0x88, 0x4b, 0xae, 0xec, 0xdb }; + +int main(int argc, char **argv) +{ + struct ext2_super_block param; + errcode_t retval; + ext2_filsys fs; + int i; + __u16 csum1, csum2, csum_known = 0xd3a4; + + memset(¶m, 0, sizeof(param)); + ext2fs_blocks_count_set(¶m, 32768); +#if 0 + param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_64BIT; + param.s_desc_size = 128; + csum_known = 0x5b6e; +#endif + + retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, ¶m, + test_io_manager, &fs); + if (retval) { + com_err("setup", retval, + "While initializing filesystem"); + exit(1); + } + memcpy(fs->super->s_uuid, sb_uuid, 16); + fs->super->s_feature_ro_compat = EXT4_FEATURE_RO_COMPAT_GDT_CSUM; + + for (i=0; i < fs->group_desc_count; i++) { + ext2fs_block_bitmap_loc_set(fs, i, 124); + ext2fs_inode_bitmap_loc_set(fs, i, 125); + ext2fs_inode_table_loc_set(fs, i, 126); + ext2fs_bg_free_blocks_count_set(fs, i, 31119); + ext2fs_bg_free_inodes_count_set(fs, i, 15701); + ext2fs_bg_used_dirs_count_set(fs, i, 2); + ext2fs_bg_flags_zap(fs, i); + }; + + csum1 = ext2fs_group_desc_csum(fs, 0); + print_csum("csum0000", fs, 0); + + if (csum1 != csum_known) { + printf("checksum for group 0 should be %04x\n", csum_known); + exit(1); + } + csum2 = ext2fs_group_desc_csum(fs, 1); + print_csum("csum0001", fs, 1); + if (csum1 == csum2) { + printf("checksums for different groups shouldn't match\n"); + exit(1); + } + csum2 = ext2fs_group_desc_csum(fs, 2); + print_csum("csumffff", fs, 2); + if (csum1 == csum2) { + printf("checksums for different groups shouldn't match\n"); + exit(1); + } + ext2fs_bg_checksum_set(fs, 0, csum1); + csum2 = ext2fs_group_desc_csum(fs, 0); + print_csum("csum_set", fs, 0); + if (csum1 != csum2) { + printf("checksums should not depend on checksum field\n"); + exit(1); + } + if (!ext2fs_group_desc_csum_verify(fs, 0)) { + printf("checksums should verify against gd_checksum\n"); + exit(1); + } + memset(fs->super->s_uuid, 0x30, sizeof(fs->super->s_uuid)); + print_csum("new_uuid", fs, 0); + if (ext2fs_group_desc_csum_verify(fs, 0) != 0) { + printf("checksums for different filesystems shouldn't match\n"); + exit(1); + } + csum1 = ext2fs_group_desc_csum(fs, 0); + ext2fs_bg_checksum_set(fs, 0, csum1); + print_csum("csum_new", fs, 0); + ext2fs_bg_free_blocks_count_set(fs, 0, 1); + csum2 = ext2fs_group_desc_csum(fs, 0); + print_csum("csum_blk", fs, 0); + if (csum1 == csum2) { + printf("checksums for different data shouldn't match\n"); + exit(1); + } + ext2fs_free(fs); + + return 0; +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/dblist.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/dblist.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,403 @@ +/* + * dblist.c -- directory block list functions + * + * Copyright 1997 by Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "ext2_fs.h" +#include "ext2fsP.h" + +static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b); +static EXT2_QSORT_TYPE dir_block_cmp2(const void *a, const void *b); +static EXT2_QSORT_TYPE (*sortfunc32)(const void *a, const void *b); + +/* + * helper function for making a new directory block list (for + * initialize and copy). + */ +static errcode_t make_dblist(ext2_filsys fs, ext2_ino_t size, + ext2_ino_t count, + struct ext2_db_entry2 *list, + ext2_dblist *ret_dblist) +{ + ext2_dblist dblist = NULL; + errcode_t retval; + ext2_ino_t num_dirs; + size_t len; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if ((ret_dblist == 0) && fs->dblist && + (fs->dblist->magic == EXT2_ET_MAGIC_DBLIST)) + return 0; + + retval = ext2fs_get_mem(sizeof(struct ext2_struct_dblist), &dblist); + if (retval) + goto cleanup; + memset(dblist, 0, sizeof(struct ext2_struct_dblist)); + + dblist->magic = EXT2_ET_MAGIC_DBLIST; + dblist->fs = fs; + if (size) + dblist->size = size; + else { + retval = ext2fs_get_num_dirs(fs, &num_dirs); + if (retval) + goto cleanup; + dblist->size = (num_dirs * 2) + 12; + } + len = (size_t) sizeof(struct ext2_db_entry2) * dblist->size; + dblist->count = count; + retval = ext2fs_get_array(dblist->size, sizeof(struct ext2_db_entry2), + &dblist->list); + if (retval) + goto cleanup; + + if (list) + memcpy(dblist->list, list, len); + else + memset(dblist->list, 0, len); + if (ret_dblist) + *ret_dblist = dblist; + else + fs->dblist = dblist; + return 0; +cleanup: + if (dblist) + ext2fs_free_mem(&dblist); + return retval; +} + +/* + * Initialize a directory block list + */ +errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist) +{ + ext2_dblist dblist; + errcode_t retval; + + retval = make_dblist(fs, 0, 0, 0, &dblist); + if (retval) + return retval; + + dblist->sorted = 1; + if (ret_dblist) + *ret_dblist = dblist; + else + fs->dblist = dblist; + + return 0; +} + +/* + * Copy a directory block list + */ +errcode_t ext2fs_copy_dblist(ext2_dblist src, ext2_dblist *dest) +{ + ext2_dblist dblist; + errcode_t retval; + + retval = make_dblist(src->fs, src->size, src->count, src->list, + &dblist); + if (retval) + return retval; + dblist->sorted = src->sorted; + *dest = dblist; + return 0; +} + +/* + * Close a directory block list + * + * (moved to closefs.c) + */ + + +/* + * Add a directory block to the directory block list + */ +errcode_t ext2fs_add_dir_block2(ext2_dblist dblist, ext2_ino_t ino, + blk64_t blk, e2_blkcnt_t blockcnt) +{ + struct ext2_db_entry2 *new_entry; + errcode_t retval; + unsigned long old_size; + + EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); + + if (dblist->count >= dblist->size) { + old_size = dblist->size * sizeof(struct ext2_db_entry2); + dblist->size += dblist->size > 200 ? dblist->size / 2 : 100; + retval = ext2fs_resize_mem(old_size, (size_t) dblist->size * + sizeof(struct ext2_db_entry2), + &dblist->list); + if (retval) { + dblist->size = old_size / sizeof(struct ext2_db_entry2); + return retval; + } + } + new_entry = dblist->list + ( dblist->count++); + new_entry->blk = blk; + new_entry->ino = ino; + new_entry->blockcnt = blockcnt; + + dblist->sorted = 0; + + return 0; +} + +/* + * Change the directory block to the directory block list + */ +errcode_t ext2fs_set_dir_block2(ext2_dblist dblist, ext2_ino_t ino, + blk64_t blk, e2_blkcnt_t blockcnt) +{ + dgrp_t i; + + EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); + + for (i=0; i < dblist->count; i++) { + if ((dblist->list[i].ino != ino) || + (dblist->list[i].blockcnt != blockcnt)) + continue; + dblist->list[i].blk = blk; + dblist->sorted = 0; + return 0; + } + return EXT2_ET_DB_NOT_FOUND; +} + +void ext2fs_dblist_sort2(ext2_dblist dblist, + EXT2_QSORT_TYPE (*sortfunc)(const void *, + const void *)) +{ + if (!sortfunc) + sortfunc = dir_block_cmp2; + qsort(dblist->list, (size_t) dblist->count, + sizeof(struct ext2_db_entry2), sortfunc); + dblist->sorted = 1; +} + +/* + * This function iterates over the directory block list + */ +errcode_t ext2fs_dblist_iterate3(ext2_dblist dblist, + int (*func)(ext2_filsys fs, + struct ext2_db_entry2 *db_info, + void *priv_data), + unsigned long long start, + unsigned long long count, + void *priv_data) +{ + unsigned long long i, end; + int ret; + + EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); + + end = start + count; + if (!dblist->sorted) + ext2fs_dblist_sort2(dblist, 0); + if (end > dblist->count) + end = dblist->count; + for (i = start; i < end; i++) { + ret = (*func)(dblist->fs, &dblist->list[i], priv_data); + if (ret & DBLIST_ABORT) + return 0; + } + return 0; +} + +errcode_t ext2fs_dblist_iterate2(ext2_dblist dblist, + int (*func)(ext2_filsys fs, + struct ext2_db_entry2 *db_info, + void *priv_data), + void *priv_data) +{ + return ext2fs_dblist_iterate3(dblist, func, 0, dblist->count, + priv_data); +} + +static EXT2_QSORT_TYPE dir_block_cmp2(const void *a, const void *b) +{ + const struct ext2_db_entry2 *db_a = + (const struct ext2_db_entry2 *) a; + const struct ext2_db_entry2 *db_b = + (const struct ext2_db_entry2 *) b; + + if (db_a->blk != db_b->blk) + return (int) (db_a->blk - db_b->blk); + + if (db_a->ino != db_b->ino) + return (int) (db_a->ino - db_b->ino); + + return (db_a->blockcnt - db_b->blockcnt); +} + +blk64_t ext2fs_dblist_count2(ext2_dblist dblist) +{ + return dblist->count; +} + +errcode_t ext2fs_dblist_get_last2(ext2_dblist dblist, + struct ext2_db_entry2 **entry) +{ + EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); + + if (dblist->count == 0) + return EXT2_ET_DBLIST_EMPTY; + + if (entry) + *entry = dblist->list + ( dblist->count-1); + return 0; +} + +errcode_t ext2fs_dblist_drop_last(ext2_dblist dblist) +{ + EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); + + if (dblist->count == 0) + return EXT2_ET_DBLIST_EMPTY; + + dblist->count--; + return 0; +} + +/* + * Legacy 32-bit versions + */ + +/* + * Add a directory block to the directory block list + */ +errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk, + int blockcnt) +{ + return ext2fs_add_dir_block2(dblist, ino, blk, blockcnt); +} + +/* + * Change the directory block to the directory block list + */ +errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk, + int blockcnt) +{ + return ext2fs_set_dir_block2(dblist, ino, blk, blockcnt); +} + +void ext2fs_dblist_sort(ext2_dblist dblist, + EXT2_QSORT_TYPE (*sortfunc)(const void *, + const void *)) +{ + if (sortfunc) { + sortfunc32 = sortfunc; + sortfunc = dir_block_cmp; + } else + sortfunc = dir_block_cmp2; + qsort(dblist->list, (size_t) dblist->count, + sizeof(struct ext2_db_entry2), sortfunc); + dblist->sorted = 1; +} + +/* + * This function iterates over the directory block list + */ +struct iterate_passthrough { + int (*func)(ext2_filsys fs, + struct ext2_db_entry *db_info, + void *priv_data); + void *priv_data; +}; + +static int passthrough_func(ext2_filsys fs, + struct ext2_db_entry2 *db_info, + void *priv_data) +{ + struct iterate_passthrough *p = priv_data; + struct ext2_db_entry db; + int ret; + + db.ino = db_info->ino; + db.blk = (blk_t) db_info->blk; + db.blockcnt = (int) db_info->blockcnt; + ret = (p->func)(fs, &db, p->priv_data); + db_info->ino = db.ino; + db_info->blk = db.blk; + db_info->blockcnt = db.blockcnt; + return ret; +} + +errcode_t ext2fs_dblist_iterate(ext2_dblist dblist, + int (*func)(ext2_filsys fs, + struct ext2_db_entry *db_info, + void *priv_data), + void *priv_data) +{ + struct iterate_passthrough pass; + + EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); + pass.func = func; + pass.priv_data = priv_data; + + return ext2fs_dblist_iterate2(dblist, passthrough_func, &pass); +} + +static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b) +{ + const struct ext2_db_entry2 *db_a = + (const struct ext2_db_entry2 *) a; + const struct ext2_db_entry2 *db_b = + (const struct ext2_db_entry2 *) b; + + struct ext2_db_entry a32, b32; + + a32.ino = db_a->ino; a32.blk = db_a->blk; + a32.blockcnt = db_a->blockcnt; + + b32.ino = db_b->ino; b32.blk = db_b->blk; + b32.blockcnt = db_b->blockcnt; + + return sortfunc32(&a32, &b32); +} + +int ext2fs_dblist_count(ext2_dblist dblist) +{ + return dblist->count; +} + +errcode_t ext2fs_dblist_get_last(ext2_dblist dblist, + struct ext2_db_entry **entry) +{ + static struct ext2_db_entry ret_entry; + struct ext2_db_entry2 *last; + + EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); + + if (dblist->count == 0) + return EXT2_ET_DBLIST_EMPTY; + + if (!entry) + return 0; + + last = dblist->list + dblist->count -1; + + ret_entry.ino = last->ino; + ret_entry.blk = last->blk; + ret_entry.blockcnt = last->blockcnt; + *entry = &ret_entry; + + return 0; +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/dblist_dir.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/dblist_dir.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,88 @@ +/* + * dblist_dir.c --- iterate by directory entry + * + * Copyright 1997 by Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "ext2_fs.h" +#include "ext2fsP.h" + +static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry2 *db_info, + void *priv_data); + +errcode_t ext2fs_dblist_dir_iterate(ext2_dblist dblist, + int flags, + char *block_buf, + int (*func)(ext2_ino_t dir, + int entry, + struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data), + void *priv_data) +{ + errcode_t retval; + struct dir_context ctx; + + EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); + + ctx.dir = 0; + ctx.flags = flags; + if (block_buf) + ctx.buf = block_buf; + else { + retval = ext2fs_get_mem(dblist->fs->blocksize, &ctx.buf); + if (retval) + return retval; + } + ctx.func = func; + ctx.priv_data = priv_data; + ctx.errcode = 0; + + retval = ext2fs_dblist_iterate2(dblist, db_dir_proc, &ctx); + + if (!block_buf) + ext2fs_free_mem(&ctx.buf); + if (retval) + return retval; + return ctx.errcode; +} + +static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry2 *db_info, + void *priv_data) +{ + struct ext2_inode inode; + struct dir_context *ctx; + int ret; + + ctx = (struct dir_context *) priv_data; + ctx->dir = db_info->ino; + ctx->errcode = 0; + + ctx->errcode = ext2fs_read_inode(fs, ctx->dir, &inode); + if (ctx->errcode) + return DBLIST_ABORT; + if (inode.i_flags & EXT4_INLINE_DATA_FL) + ret = ext2fs_inline_data_dir_iterate(fs, ctx->dir, ctx); + else + ret = ext2fs_process_dir_block(fs, &db_info->blk, + db_info->blockcnt, 0, 0, + priv_data); + if ((ret & BLOCK_ABORT) && !ctx->errcode) + return DBLIST_ABORT; + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/digest_encode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/digest_encode.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,187 @@ +/* + * lib/ext2fs/digest_encode.c + * + * A function to encode a digest using 64 characters that are valid in a + * filename per ext2fs rules. + * + * Written by Uday Savagaonkar, 2014. + * + * Copyright 2014 Google Inc. All Rights Reserved. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#if HAVE_SYS_TYPES_H +#include +#endif +#include "ext2fs.h" + +static const char *lookup_table = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; + +/** + * ext2fs_digest_encode() - + * + * Encodes the input digest using characters from the set [a-zA-Z0-9_+]. + * The encoded string is roughly 4/3 times the size of the input string. + */ +int ext2fs_digest_encode(const char *src, int len, char *dst) +{ + int i = 0, bits = 0, ac = 0; + char *cp = dst; + + while (i < len) { + ac += (((unsigned char) src[i]) << bits); + bits += 8; + do { + *cp++ = lookup_table[ac & 0x3f]; + ac >>= 6; + bits -= 6; + } while (bits >= 6); + i++; + } + if (bits) + *cp++ = lookup_table[ac & 0x3f]; + return cp - dst; +} + +int ext2fs_digest_decode(const char *src, int len, char *dst) +{ + int i = 0, bits = 0, ac = 0; + const char *p; + char *cp = dst; + + while (i < len) { + p = strchr(lookup_table, src[i]); + if (p == NULL || src[i] == 0) + return -1; + ac += (p - lookup_table) << bits; + bits += 6; + if (bits >= 8) { + *cp++ = ac & 0xff; + ac >>= 8; + bits -= 8; + } + i++; + } + if (ac) + return -1; + return cp - dst; +} + + +#ifdef UNITTEST +static const struct { + unsigned char d[32]; + unsigned int len; + const char *ed; +} tests[] = { + { { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, + 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, + 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 }, 32, + "jDLxChJ,cQhm7TPyZ+WukcirBROZbOJTkWZmbgnU4WF" + }, + { { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }, 32, + "6inF,+YAPreQBBk3d5qIjA7AhNqlXoHn0Cx,hJPAV0K" + }, + { { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, + 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, + 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }, 32, + "k0oahJtB4gb5AbykM4DY5MKPknFZ,HyZ2ze7Unx2GEM" + }, + { { 0x00, }, 1, + "AA" + }, + { { 0x01, }, 1, + "BA" + }, + { { 0x01, 0x02 }, 2, + "BIA" + }, + { { 0x01, 0x02, 0x03 }, 3, + "BIwA" + }, + { { 0x01, 0x02, 0x03, 0x04 }, 4, + "BIwAEA" + }, + { { 0x01, 0x02, 0x03, 0x04, 0xff }, 5, + "BIwAE8P" + }, + { { 0x01, 0x02, 0x03, 0x04, 0xff, 0xfe }, 6, + "BIwAE8v," + }, + { { 0x01, 0x02, 0x03, 0x04, 0xff, 0xfe, 0xfd }, 7, + "BIwAE8v,9D" + }, +}; + +int main(int argc, char **argv) +{ + int i, ret, len; + int errors = 0; + char tmp[1024], tmp2[1024]; + + if (argc == 3 && !strcmp(argv[1], "encode")) { + memset(tmp, 0, sizeof(tmp)); + ext2fs_digest_encode(argv[2], strlen(argv[2]), tmp); + puts(tmp); + exit(0); + } + if (argc == 3 && !strcmp(argv[1], "decode")) { + memset(tmp, 0, sizeof(tmp)); + ret = ext2fs_digest_decode(argv[2], strlen(argv[2]), tmp); + puts(tmp); + fprintf(stderr, "returned %d\n", ret); + exit(0); + } + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + memset(tmp, 0, sizeof(tmp)); + ret = ext2fs_digest_encode((const char *) tests[i].d, + tests[i].len, tmp); + len = strlen(tmp); + printf("Test Digest %d (returned %d): ", i, ret); + if (ret != len) { + printf("FAILED returned %d, string length was %d\n", + ret, len); + errors++; + continue; + } else if (strcmp(tmp, tests[i].ed) != 0) { + printf("FAILED: got %s, expected %s\n", tmp, + tests[i].ed); + errors++; + continue; + } + ret = ext2fs_digest_decode(tmp, len, tmp2); + if (ret != tests[i].len) { + printf("FAILED decode returned %d, expected %d\n", + ret, tests[i].len); + errors++; + continue; + } + if (memcmp(tmp2, tests[i].d, ret) != 0) { + puts("FAILED: decode mismatched"); + errors++; + continue; + } + printf("OK\n"); + } + for (i = 1; i < argc; i++) { + memset(tmp, 0, sizeof(tmp)); + ret = ext2fs_digest_encode(argv[i], strlen(argv[i]), tmp); + len = strlen(tmp); + printf("Digest of '%s' is '%s' (returned %d, length %d)\n", + argv[i], tmp, ret, len); + } + return errors; +} + +#endif /* UNITTEST */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/dir_iterate.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/dir_iterate.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,311 @@ +/* + * dir_iterate.c --- ext2fs directory iteration operations + * + * Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" + +#define EXT4_MAX_REC_LEN ((1<<16)-1) + +errcode_t ext2fs_get_rec_len(ext2_filsys fs, + struct ext2_dir_entry *dirent, + unsigned int *rec_len) +{ + unsigned int len = dirent->rec_len; + + if (fs->blocksize < 65536) + *rec_len = len; + else if (len == EXT4_MAX_REC_LEN || len == 0) + *rec_len = fs->blocksize; + else + *rec_len = (len & 65532) | ((len & 3) << 16); + return 0; +} + +errcode_t ext2fs_set_rec_len(ext2_filsys fs, + unsigned int len, + struct ext2_dir_entry *dirent) +{ + if ((len > fs->blocksize) || (fs->blocksize > (1 << 18)) || (len & 3)) + return EINVAL; + if (len < 65536) { + dirent->rec_len = len; + return 0; + } + if (len == fs->blocksize) { + if (fs->blocksize == 65536) + dirent->rec_len = EXT4_MAX_REC_LEN; + else + dirent->rec_len = 0; + } else + dirent->rec_len = (len & 65532) | ((len >> 16) & 3); + return 0; +} + +/* + * This function checks to see whether or not a potential deleted + * directory entry looks valid. What we do is check the deleted entry + * and each successive entry to make sure that they all look valid and + * that the last deleted entry ends at the beginning of the next + * undeleted entry. Returns 1 if the deleted entry looks valid, zero + * if not valid. + */ +static int ext2fs_validate_entry(ext2_filsys fs, char *buf, + unsigned int offset, + unsigned int final_offset) +{ + struct ext2_dir_entry *dirent; + unsigned int rec_len; +#define DIRENT_MIN_LENGTH 12 + + while ((offset < final_offset) && + (offset <= fs->blocksize - DIRENT_MIN_LENGTH)) { + dirent = (struct ext2_dir_entry *)(buf + offset); + if (ext2fs_get_rec_len(fs, dirent, &rec_len)) + return 0; + offset += rec_len; + if ((rec_len < 8) || + ((rec_len % 4) != 0) || + ((ext2fs_dirent_name_len(dirent)+8) > (int) rec_len)) + return 0; + } + return (offset == final_offset); +} + +errcode_t ext2fs_dir_iterate2(ext2_filsys fs, + ext2_ino_t dir, + int flags, + char *block_buf, + int (*func)(ext2_ino_t dir, + int entry, + struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data), + void *priv_data) +{ + struct dir_context ctx; + errcode_t retval; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + retval = ext2fs_check_directory(fs, dir); + if (retval) + return retval; + + ctx.dir = dir; + ctx.flags = flags; + if (block_buf) + ctx.buf = block_buf; + else { + retval = ext2fs_get_mem(fs->blocksize, &ctx.buf); + if (retval) + return retval; + } + ctx.func = func; + ctx.priv_data = priv_data; + ctx.errcode = 0; + retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY, 0, + ext2fs_process_dir_block, &ctx); + if (!block_buf) + ext2fs_free_mem(&ctx.buf); + if (retval == EXT2_ET_INLINE_DATA_CANT_ITERATE) { + (void) ext2fs_inline_data_dir_iterate(fs, dir, &ctx); + retval = 0; + } + if (retval) + return retval; + return ctx.errcode; +} + +struct xlate { + int (*func)(struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data); + void *real_private; +}; + +static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)), + int entry EXT2FS_ATTR((unused)), + struct ext2_dir_entry *dirent, int offset, + int blocksize, char *buf, void *priv_data) +{ + struct xlate *xl = (struct xlate *) priv_data; + + return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private); +} + +errcode_t ext2fs_dir_iterate(ext2_filsys fs, + ext2_ino_t dir, + int flags, + char *block_buf, + int (*func)(struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data), + void *priv_data) +{ + struct xlate xl; + + xl.real_private = priv_data; + xl.func = func; + + return ext2fs_dir_iterate2(fs, dir, flags, block_buf, + xlate_func, &xl); +} + + +/* + * Helper function which is private to this module. Used by + * ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate() + */ +int ext2fs_process_dir_block(ext2_filsys fs, + blk64_t *blocknr, + e2_blkcnt_t blockcnt, + blk64_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct dir_context *ctx = (struct dir_context *) priv_data; + unsigned int offset = 0; + unsigned int next_real_entry = 0; + int ret = 0; + int changed = 0; + int do_abort = 0; + unsigned int rec_len, size, buflen; + int entry; + struct ext2_dir_entry *dirent; + int csum_size = 0; + int inline_data; + errcode_t retval = 0; + + if (blockcnt < 0) + return 0; + + entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE; + + /* If a dir has inline data, we don't need to read block */ + inline_data = !!(ctx->flags & DIRENT_FLAG_INCLUDE_INLINE_DATA); + if (!inline_data) { + ctx->errcode = ext2fs_read_dir_block4(fs, *blocknr, ctx->buf, 0, + ctx->dir); + if (ctx->errcode) + return BLOCK_ABORT; + /* If we handle a normal dir, we traverse the entire block */ + buflen = fs->blocksize; + } else { + buflen = ctx->buflen; + } + + if (ext2fs_has_feature_metadata_csum(fs->super)) + csum_size = sizeof(struct ext2_dir_entry_tail); + + while (offset < buflen - 8) { + dirent = (struct ext2_dir_entry *) (ctx->buf + offset); + if (ext2fs_get_rec_len(fs, dirent, &rec_len)) + return BLOCK_ABORT; + if (((offset + rec_len) > buflen) || + (rec_len < 8) || + ((rec_len % 4) != 0) || + ((ext2fs_dirent_name_len(dirent)+8) > (int) rec_len)) { + ctx->errcode = EXT2_ET_DIR_CORRUPTED; + return BLOCK_ABORT; + } + if (!dirent->inode) { + /* + * We just need to check metadata_csum when this + * dir hasn't inline data. That means that 'buflen' + * should be blocksize. + */ + if (!inline_data && + (offset == buflen - csum_size) && + (dirent->rec_len == csum_size) && + (dirent->name_len == EXT2_DIR_NAME_LEN_CSUM)) { + if (!(ctx->flags & DIRENT_FLAG_INCLUDE_CSUM)) + goto next; + entry = DIRENT_CHECKSUM; + } else if (!(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY)) + goto next; + } + + ret = (ctx->func)(ctx->dir, + (next_real_entry > offset) ? + DIRENT_DELETED_FILE : entry, + dirent, offset, + buflen, ctx->buf, + ctx->priv_data); + if (entry < DIRENT_OTHER_FILE) + entry++; + + if (ret & DIRENT_CHANGED) { + if (ext2fs_get_rec_len(fs, dirent, &rec_len)) + return BLOCK_ABORT; + changed++; + } + if (ret & DIRENT_ABORT) { + do_abort++; + break; + } +next: + if (next_real_entry == offset) + next_real_entry += rec_len; + + if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) { + size = (ext2fs_dirent_name_len(dirent) + 11) & ~3; + + if (rec_len != size) { + unsigned int final_offset; + + final_offset = offset + rec_len; + offset += size; + while (offset < final_offset && + !ext2fs_validate_entry(fs, ctx->buf, + offset, + final_offset)) + offset += 4; + continue; + } + } + offset += rec_len; + } + + if (changed) { + if (!inline_data) { + ctx->errcode = ext2fs_write_dir_block4(fs, *blocknr, + ctx->buf, + 0, ctx->dir); + if (ctx->errcode) + return BLOCK_ABORT; + } else { + /* + * return BLOCK_INLINE_DATA_CHANGED to notify caller + * that inline data has been changed. + */ + retval = BLOCK_INLINE_DATA_CHANGED; + } + } + if (do_abort) + return retval | BLOCK_ABORT; + return retval; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/dirblock.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/dirblock.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,113 @@ +/* + * dirblock.c --- directory block routines. + * + * Copyright (C) 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "ext2_fs.h" +#include "ext2fs.h" + +errcode_t ext2fs_read_dir_block4(ext2_filsys fs, blk64_t block, + void *buf, int flags EXT2FS_ATTR((unused)), + ext2_ino_t ino) +{ + errcode_t retval; + int corrupt = 0; + + retval = io_channel_read_blk64(fs->io, block, 1, buf); + if (retval) + return retval; + + if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_dir_block_csum_verify(fs, ino, + (struct ext2_dir_entry *)buf)) + corrupt = 1; + +#ifdef WORDS_BIGENDIAN + retval = ext2fs_dirent_swab_in(fs, buf, flags); +#endif + if (!retval && corrupt) + retval = EXT2_ET_DIR_CSUM_INVALID; + return retval; +} + +errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block, + void *buf, int flags EXT2FS_ATTR((unused))) +{ + return ext2fs_read_dir_block4(fs, block, buf, flags, 0); +} + +errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block, + void *buf, int flags EXT2FS_ATTR((unused))) +{ + return ext2fs_read_dir_block3(fs, block, buf, flags); +} + +errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block, + void *buf) +{ + return ext2fs_read_dir_block3(fs, block, buf, 0); +} + + +errcode_t ext2fs_write_dir_block4(ext2_filsys fs, blk64_t block, + void *inbuf, int flags EXT2FS_ATTR((unused)), + ext2_ino_t ino) +{ + errcode_t retval; + char *buf = inbuf; + +#ifdef WORDS_BIGENDIAN + retval = ext2fs_get_mem(fs->blocksize, &buf); + if (retval) + return retval; + memcpy(buf, inbuf, fs->blocksize); + retval = ext2fs_dirent_swab_out(fs, buf, flags); + if (retval) + return retval; +#endif + retval = ext2fs_dir_block_csum_set(fs, ino, + (struct ext2_dir_entry *)buf); + if (retval) + goto out; + + retval = io_channel_write_blk64(fs->io, block, 1, buf); + +out: +#ifdef WORDS_BIGENDIAN + ext2fs_free_mem(&buf); +#endif + return retval; +} + +errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block, + void *inbuf, int flags EXT2FS_ATTR((unused))) +{ + return ext2fs_write_dir_block4(fs, block, inbuf, flags, 0); +} + +errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block, + void *inbuf, int flags EXT2FS_ATTR((unused))) +{ + return ext2fs_write_dir_block3(fs, block, inbuf, flags); +} + +errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block, + void *inbuf) +{ + return ext2fs_write_dir_block3(fs, block, inbuf, 0); +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/dirhash.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/dirhash.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,259 @@ +/* + * dirhash.c -- Calculate the hash of a directory entry + * + * Copyright (c) 2001 Daniel Phillips + * + * Copyright (c) 2002 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include + +#include "ext2_fs.h" +#include "ext2fs.h" + +/* + * Keyed 32-bit hash function using TEA in a Davis-Meyer function + * H0 = Key + * Hi = E Mi(Hi-1) + Hi-1 + * + * (see Applied Cryptography, 2nd edition, p448). + * + * Jeremy Fitzhardinge 1998 + * + * This code is made available under the terms of the GPL + */ +#define DELTA 0x9E3779B9 + +static void TEA_transform(__u32 buf[4], __u32 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; +} + +/* F, G and H are basic MD4 functions: selection, majority, parity */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +/* + * The generic round function. The application is so specific that + * we don't bother protecting all the arguments with parens, as is generally + * good macro practice, in favor of extra legibility. + * Rotation is separate from addition to prevent recomputation + */ +#define ROUND(f, a, b, c, d, x, s) \ + (a += f(b, c, d) + x, a = (a << s) | (a >> (32-s))) +#define K1 0 +#define K2 013240474631UL +#define K3 015666365641UL + +/* + * Basic cut-down MD4 transform. Returns only 32 bits of result. + */ +static void halfMD4Transform (__u32 buf[4], __u32 const in[]) +{ + __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ + ROUND(F, a, b, c, d, in[0] + K1, 3); + ROUND(F, d, a, b, c, in[1] + K1, 7); + ROUND(F, c, d, a, b, in[2] + K1, 11); + ROUND(F, b, c, d, a, in[3] + K1, 19); + ROUND(F, a, b, c, d, in[4] + K1, 3); + ROUND(F, d, a, b, c, in[5] + K1, 7); + ROUND(F, c, d, a, b, in[6] + K1, 11); + ROUND(F, b, c, d, a, in[7] + K1, 19); + + /* Round 2 */ + ROUND(G, a, b, c, d, in[1] + K2, 3); + ROUND(G, d, a, b, c, in[3] + K2, 5); + ROUND(G, c, d, a, b, in[5] + K2, 9); + ROUND(G, b, c, d, a, in[7] + K2, 13); + ROUND(G, a, b, c, d, in[0] + K2, 3); + ROUND(G, d, a, b, c, in[2] + K2, 5); + ROUND(G, c, d, a, b, in[4] + K2, 9); + ROUND(G, b, c, d, a, in[6] + K2, 13); + + /* Round 3 */ + ROUND(H, a, b, c, d, in[3] + K3, 3); + ROUND(H, d, a, b, c, in[7] + K3, 9); + ROUND(H, c, d, a, b, in[2] + K3, 11); + ROUND(H, b, c, d, a, in[6] + K3, 15); + ROUND(H, a, b, c, d, in[1] + K3, 3); + ROUND(H, d, a, b, c, in[5] + K3, 9); + ROUND(H, c, d, a, b, in[0] + K3, 11); + ROUND(H, b, c, d, a, in[4] + K3, 15); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#undef ROUND +#undef F +#undef G +#undef H +#undef K1 +#undef K2 +#undef K3 + +/* The old legacy hash */ +static ext2_dirhash_t dx_hack_hash (const char *name, int len, + int unsigned_flag) +{ + __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; + const unsigned char *ucp = (const unsigned char *) name; + const signed char *scp = (const signed char *) name; + int c; + + while (len--) { + if (unsigned_flag) + c = (int) *ucp++; + else + c = (int) *scp++; + hash = hash1 + (hash0 ^ (c * 7152373)); + + if (hash & 0x80000000) hash -= 0x7fffffff; + hash1 = hash0; + hash0 = hash; + } + return (hash0 << 1); +} + +static void str2hashbuf(const char *msg, int len, __u32 *buf, int num, + int unsigned_flag) +{ + __u32 pad, val; + int i, c; + const unsigned char *ucp = (const unsigned char *) msg; + const signed char *scp = (const signed char *) msg; + + 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 (unsigned_flag) + c = (int) ucp[i]; + else + c = (int) scp[i]; + + val = c + (val << 8); + if ((i % 4) == 3) { + *buf++ = val; + val = pad; + num--; + } + } + if (--num >= 0) + *buf++ = val; + while (--num >= 0) + *buf++ = pad; +} + +/* + * Returns the hash of a filename. If len is 0 and name is NULL, then + * this function can be used to test whether or not a hash version is + * supported. + * + * The seed is an 4 longword (32 bits) "secret" which can be used to + * uniquify a hash. If the seed is all zero's, then some default seed + * may be used. + * + * A particular hash version specifies whether or not the seed is + * represented, and whether or not the returned hash is 32 bits or 64 + * bits. 32 bit hashes will return 0 for the minor hash. + */ +errcode_t ext2fs_dirhash(int version, const char *name, int len, + const __u32 *seed, + ext2_dirhash_t *ret_hash, + ext2_dirhash_t *ret_minor_hash) +{ + __u32 hash; + __u32 minor_hash = 0; + const char *p; + int i; + __u32 in[8], buf[4]; + int unsigned_flag = 0; + + /* Initialize the default seed for the hash checksum functions */ + buf[0] = 0x67452301; + buf[1] = 0xefcdab89; + buf[2] = 0x98badcfe; + buf[3] = 0x10325476; + + /* Check to see if the seed is all zero's */ + if (seed) { + for (i=0; i < 4; i++) { + if (seed[i]) + break; + } + if (i < 4) + memcpy(buf, seed, sizeof(buf)); + } + + switch (version) { + case EXT2_HASH_LEGACY_UNSIGNED: + unsigned_flag++; + /* fallthrough */ + case EXT2_HASH_LEGACY: + hash = dx_hack_hash(name, len, unsigned_flag); + break; + case EXT2_HASH_HALF_MD4_UNSIGNED: + unsigned_flag++; + /* fallthrough */ + case EXT2_HASH_HALF_MD4: + p = name; + while (len > 0) { + str2hashbuf(p, len, in, 8, unsigned_flag); + halfMD4Transform(buf, in); + len -= 32; + p += 32; + } + minor_hash = buf[2]; + hash = buf[1]; + break; + case EXT2_HASH_TEA_UNSIGNED: + unsigned_flag++; + /* fallthrough */ + case EXT2_HASH_TEA: + p = name; + while (len > 0) { + str2hashbuf(p, len, in, 4, unsigned_flag); + TEA_transform(buf, in); + len -= 16; + p += 16; + } + hash = buf[0]; + minor_hash = buf[1]; + break; + default: + *ret_hash = 0; + return EXT2_ET_DIRHASH_UNSUPP; + } + *ret_hash = hash & ~1; + if (ret_minor_hash) + *ret_minor_hash = minor_hash; + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/dupfs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/dupfs.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,122 @@ +/* + * dupfs.c --- duplicate a ext2 filesystem handle + * + * Copyright (C) 1997, 1998, 2001, 2003, 2005 by Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "ext2_fs.h" +#include "ext2fsP.h" + +errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest) +{ + ext2_filsys fs; + errcode_t retval; + + EXT2_CHECK_MAGIC(src, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs); + if (retval) + return retval; + + *fs = *src; + fs->device_name = 0; + fs->super = 0; + fs->orig_super = 0; + fs->group_desc = 0; + fs->inode_map = 0; + fs->block_map = 0; + fs->badblocks = 0; + fs->dblist = 0; + fs->mmp_buf = 0; + fs->mmp_cmp = 0; + fs->mmp_fd = -1; + + io_channel_bumpcount(fs->io); + if (fs->icache) + fs->icache->refcount++; + + retval = ext2fs_get_mem(strlen(src->device_name)+1, &fs->device_name); + if (retval) + goto errout; + strcpy(fs->device_name, src->device_name); + + retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super); + if (retval) + goto errout; + memcpy(fs->super, src->super, SUPERBLOCK_SIZE); + + retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super); + if (retval) + goto errout; + memcpy(fs->orig_super, src->orig_super, SUPERBLOCK_SIZE); + + retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize, + &fs->group_desc); + if (retval) + goto errout; + memcpy(fs->group_desc, src->group_desc, + (size_t) fs->desc_blocks * fs->blocksize); + + if (src->inode_map) { + retval = ext2fs_copy_bitmap(src->inode_map, &fs->inode_map); + if (retval) + goto errout; + } + if (src->block_map) { + retval = ext2fs_copy_bitmap(src->block_map, &fs->block_map); + if (retval) + goto errout; + } + if (src->badblocks) { + retval = ext2fs_badblocks_copy(src->badblocks, &fs->badblocks); + if (retval) + goto errout; + } + if (src->dblist) { + retval = ext2fs_copy_dblist(src->dblist, &fs->dblist); + if (retval) + goto errout; + } + if (src->mmp_buf) { + retval = ext2fs_get_mem(src->blocksize, &fs->mmp_buf); + if (retval) + goto errout; + memcpy(fs->mmp_buf, src->mmp_buf, src->blocksize); + } + if (src->mmp_fd >= 0) { + fs->mmp_fd = dup(src->mmp_fd); + if (fs->mmp_fd < 0) { + retval = EXT2_ET_MMP_OPEN_DIRECT; + goto errout; + } + } + if (src->mmp_cmp) { + int align = ext2fs_get_dio_alignment(src->mmp_fd); + + retval = ext2fs_get_memalign(src->blocksize, align, + &fs->mmp_cmp); + if (retval) + goto errout; + memcpy(fs->mmp_cmp, src->mmp_cmp, src->blocksize); + } + *dest = fs; + return 0; +errout: + ext2fs_free(fs); + return retval; + +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/e2image.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/e2image.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,37 @@ +/* + * e2image.h --- header file describing the ext2 image format + * + * Copyright (C) 2000 Theodore Ts'o. + * + * Note: this uses the POSIX IO interfaces, unlike most of the other + * functions in this library. So sue me. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +struct ext2_image_hdr { + __u32 magic_number; /* This must be EXT2_ET_MAGIC_E2IMAGE */ + char magic_descriptor[16]; /* "Ext2 Image 1.0", w/ null padding */ + char fs_hostname[64];/* Hostname of machine of image */ + char fs_netaddr[32]; /* Network address */ + __u32 fs_netaddr_type;/* 0 = IPV4, 1 = IPV6, etc. */ + __u32 fs_device; /* Device number of image */ + char fs_device_name[64]; /* Device name */ + char fs_uuid[16]; /* UUID of filesystem */ + __u32 fs_blocksize; /* Block size of the filesystem */ + __u32 fs_reserved[8]; + + __u32 image_device; /* Device number of image file */ + __u32 image_inode; /* Inode number of image file */ + __u32 image_time; /* Time of image creation */ + __u32 image_reserved[8]; + + __u32 offset_super; /* Byte offset of the sb and descriptors */ + __u32 offset_inode; /* Byte offset of the inode table */ + __u32 offset_inodemap; /* Byte offset of the inode bitmaps */ + __u32 offset_blockmap; /* Byte offset of the inode bitmaps */ + __u32 offset_reserved[8]; +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/expanddir.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/expanddir.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,140 @@ +/* + * expand.c --- expand an ext2fs directory + * + * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +struct expand_dir_struct { + int done; + int newblocks; + blk64_t goal; + errcode_t err; + ext2_ino_t dir; +}; + +static int expand_dir_proc(ext2_filsys fs, + blk64_t *blocknr, + e2_blkcnt_t blockcnt, + blk64_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data; + blk64_t new_blk; + char *block; + errcode_t retval; + + if (*blocknr) { + if (blockcnt >= 0) + es->goal = *blocknr; + return 0; + } + if (blockcnt && + (EXT2FS_B2C(fs, es->goal) == EXT2FS_B2C(fs, es->goal+1))) + new_blk = es->goal+1; + else { + es->goal &= ~EXT2FS_CLUSTER_MASK(fs); + retval = ext2fs_new_block2(fs, es->goal, 0, &new_blk); + if (retval) { + es->err = retval; + return BLOCK_ABORT; + } + es->newblocks++; + ext2fs_block_alloc_stats2(fs, new_blk, +1); + } + if (blockcnt > 0) { + retval = ext2fs_new_dir_block(fs, 0, 0, &block); + if (retval) { + es->err = retval; + return BLOCK_ABORT; + } + es->done = 1; + retval = ext2fs_write_dir_block4(fs, new_blk, block, 0, + es->dir); + ext2fs_free_mem(&block); + } else + retval = ext2fs_zero_blocks2(fs, new_blk, 1, NULL, NULL); + if (blockcnt >= 0) + es->goal = new_blk; + if (retval) { + es->err = retval; + return BLOCK_ABORT; + } + *blocknr = new_blk; + + if (es->done) + return (BLOCK_CHANGED | BLOCK_ABORT); + else + return BLOCK_CHANGED; +} + +errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir) +{ + errcode_t retval; + struct expand_dir_struct es; + struct ext2_inode inode; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!(fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + if (!fs->block_map) + return EXT2_ET_NO_BLOCK_BITMAP; + + retval = ext2fs_check_directory(fs, dir); + if (retval) + return retval; + + retval = ext2fs_read_inode(fs, dir, &inode); + if (retval) + return retval; + + es.done = 0; + es.err = 0; + es.goal = ext2fs_find_inode_goal(fs, dir, &inode, 0); + es.newblocks = 0; + es.dir = dir; + + retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND, + 0, expand_dir_proc, &es); + if (retval == EXT2_ET_INLINE_DATA_CANT_ITERATE) + return ext2fs_inline_data_expand(fs, dir); + + if (es.err) + return es.err; + if (!es.done) + return EXT2_ET_EXPAND_DIR_ERR; + + /* + * Update the size and block count fields in the inode. + */ + retval = ext2fs_read_inode(fs, dir, &inode); + if (retval) + return retval; + + inode.i_size += fs->blocksize; + ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); + + retval = ext2fs_write_inode(fs, dir, &inode); + if (retval) + return retval; + + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/ext2_err.et.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/ext2_err.et.in Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,548 @@ +# +# Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. +# +# %Begin-Header% +# This file may be redistributed under the terms of the GNU Public +# License. +# %End-Header% +# + error_table ext2 + +ec EXT2_ET_BASE, + "EXT2FS Library version @E2FSPROGS_VERSION@" + +ec EXT2_ET_MAGIC_EXT2FS_FILSYS, + "Wrong magic number for ext2_filsys structure" + +ec EXT2_ET_MAGIC_BADBLOCKS_LIST, + "Wrong magic number for badblocks_list structure" + +ec EXT2_ET_MAGIC_BADBLOCKS_ITERATE, + "Wrong magic number for badblocks_iterate structure" + +ec EXT2_ET_MAGIC_INODE_SCAN, + "Wrong magic number for inode_scan structure" + +ec EXT2_ET_MAGIC_IO_CHANNEL, + "Wrong magic number for io_channel structure" + +ec EXT2_ET_MAGIC_UNIX_IO_CHANNEL, + "Wrong magic number for unix io_channel structure" + +ec EXT2_ET_MAGIC_IO_MANAGER, + "Wrong magic number for io_manager structure" + +ec EXT2_ET_MAGIC_BLOCK_BITMAP, + "Wrong magic number for block_bitmap structure" + +ec EXT2_ET_MAGIC_INODE_BITMAP, + "Wrong magic number for inode_bitmap structure" + +ec EXT2_ET_MAGIC_GENERIC_BITMAP, + "Wrong magic number for generic_bitmap structure" + +ec EXT2_ET_MAGIC_TEST_IO_CHANNEL, + "Wrong magic number for test io_channel structure" + +ec EXT2_ET_MAGIC_DBLIST, + "Wrong magic number for directory block list structure" + +ec EXT2_ET_MAGIC_ICOUNT, + "Wrong magic number for icount structure" + +ec EXT2_ET_MAGIC_PQ_IO_CHANNEL, + "Wrong magic number for Powerquest io_channel structure" + +ec EXT2_ET_MAGIC_EXT2_FILE, + "Wrong magic number for ext2 file structure" + +ec EXT2_ET_MAGIC_E2IMAGE, + "Wrong magic number for Ext2 Image Header" + +ec EXT2_ET_MAGIC_INODE_IO_CHANNEL, + "Wrong magic number for inode io_channel structure" + +ec EXT2_ET_MAGIC_EXTENT_HANDLE, + "Wrong magic number for ext4 extent handle" + +ec EXT2_ET_BAD_MAGIC, + "Bad magic number in super-block" + +ec EXT2_ET_REV_TOO_HIGH, + "Filesystem revision too high" + +ec EXT2_ET_RO_FILSYS, + "Attempt to write to filesystem opened read-only" + +ec EXT2_ET_GDESC_READ, + "Can't read group descriptors" + +ec EXT2_ET_GDESC_WRITE, + "Can't write group descriptors" + +ec EXT2_ET_GDESC_BAD_BLOCK_MAP, + "Corrupt group descriptor: bad block for block bitmap" + +ec EXT2_ET_GDESC_BAD_INODE_MAP, + "Corrupt group descriptor: bad block for inode bitmap" + +ec EXT2_ET_GDESC_BAD_INODE_TABLE, + "Corrupt group descriptor: bad block for inode table" + +ec EXT2_ET_INODE_BITMAP_WRITE, + "Can't write an inode bitmap" + +ec EXT2_ET_INODE_BITMAP_READ, + "Can't read an inode bitmap" + +ec EXT2_ET_BLOCK_BITMAP_WRITE, + "Can't write a block bitmap" + +ec EXT2_ET_BLOCK_BITMAP_READ, + "Can't read a block bitmap" + +ec EXT2_ET_INODE_TABLE_WRITE, + "Can't write an inode table" + +ec EXT2_ET_INODE_TABLE_READ, + "Can't read an inode table" + +ec EXT2_ET_NEXT_INODE_READ, + "Can't read next inode" + +ec EXT2_ET_UNEXPECTED_BLOCK_SIZE, + "Filesystem has unexpected block size" + +ec EXT2_ET_DIR_CORRUPTED, + "EXT2 directory corrupted" + +ec EXT2_ET_SHORT_READ, + "Attempt to read block from filesystem resulted in short read" + +ec EXT2_ET_SHORT_WRITE, + "Attempt to write block to filesystem resulted in short write" + +ec EXT2_ET_DIR_NO_SPACE, + "No free space in the directory" + +ec EXT2_ET_NO_INODE_BITMAP, + "Inode bitmap not loaded" + +ec EXT2_ET_NO_BLOCK_BITMAP, + "Block bitmap not loaded" + +ec EXT2_ET_BAD_INODE_NUM, + "Illegal inode number" + +ec EXT2_ET_BAD_BLOCK_NUM, + "Illegal block number" + +ec EXT2_ET_EXPAND_DIR_ERR, + "Internal error in ext2fs_expand_dir" + +ec EXT2_ET_TOOSMALL, + "Not enough space to build proposed filesystem" + +ec EXT2_ET_BAD_BLOCK_MARK, + "Illegal block number passed to ext2fs_mark_block_bitmap" + +ec EXT2_ET_BAD_BLOCK_UNMARK, + "Illegal block number passed to ext2fs_unmark_block_bitmap" + +ec EXT2_ET_BAD_BLOCK_TEST, + "Illegal block number passed to ext2fs_test_block_bitmap" + +ec EXT2_ET_BAD_INODE_MARK, + "Illegal inode number passed to ext2fs_mark_inode_bitmap" + +ec EXT2_ET_BAD_INODE_UNMARK, + "Illegal inode number passed to ext2fs_unmark_inode_bitmap" + +ec EXT2_ET_BAD_INODE_TEST, + "Illegal inode number passed to ext2fs_test_inode_bitmap" + +ec EXT2_ET_FUDGE_BLOCK_BITMAP_END, + "Attempt to fudge end of block bitmap past the real end" + +ec EXT2_ET_FUDGE_INODE_BITMAP_END, + "Attempt to fudge end of inode bitmap past the real end" + +ec EXT2_ET_BAD_IND_BLOCK, + "Illegal indirect block found" + +ec EXT2_ET_BAD_DIND_BLOCK, + "Illegal doubly indirect block found" + +ec EXT2_ET_BAD_TIND_BLOCK, + "Illegal triply indirect block found" + +ec EXT2_ET_NEQ_BLOCK_BITMAP, + "Block bitmaps are not the same" + +ec EXT2_ET_NEQ_INODE_BITMAP, + "Inode bitmaps are not the same" + +ec EXT2_ET_BAD_DEVICE_NAME, + "Illegal or malformed device name" + +ec EXT2_ET_MISSING_INODE_TABLE, + "A block group is missing an inode table" + +ec EXT2_ET_CORRUPT_SUPERBLOCK, + "The ext2 superblock is corrupt" + +ec EXT2_ET_BAD_GENERIC_MARK, + "Illegal generic bit number passed to ext2fs_mark_generic_bitmap" + +ec EXT2_ET_BAD_GENERIC_UNMARK, + "Illegal generic bit number passed to ext2fs_unmark_generic_bitmap" + +ec EXT2_ET_BAD_GENERIC_TEST, + "Illegal generic bit number passed to ext2fs_test_generic_bitmap" + +ec EXT2_ET_SYMLINK_LOOP, + "Too many symbolic links encountered." + +ec EXT2_ET_CALLBACK_NOTHANDLED, + "The callback function will not handle this case" + +ec EXT2_ET_BAD_BLOCK_IN_INODE_TABLE, + "The inode is from a bad block in the inode table" + +ec EXT2_ET_UNSUPP_FEATURE, + "Filesystem has unsupported feature(s)" + +ec EXT2_ET_RO_UNSUPP_FEATURE, + "Filesystem has unsupported read-only feature(s)" + +ec EXT2_ET_LLSEEK_FAILED, + "IO Channel failed to seek on read or write" + +ec EXT2_ET_NO_MEMORY, + "Memory allocation failed" + +ec EXT2_ET_INVALID_ARGUMENT, + "Invalid argument passed to ext2 library" + +ec EXT2_ET_BLOCK_ALLOC_FAIL, + "Could not allocate block in ext2 filesystem" + +ec EXT2_ET_INODE_ALLOC_FAIL, + "Could not allocate inode in ext2 filesystem" + +ec EXT2_ET_NO_DIRECTORY, + "Ext2 inode is not a directory" + +ec EXT2_ET_TOO_MANY_REFS, + "Too many references in table" + +ec EXT2_ET_FILE_NOT_FOUND, + "File not found by ext2_lookup" + +ec EXT2_ET_FILE_RO, + "File open read-only" + +ec EXT2_ET_DB_NOT_FOUND, + "Ext2 directory block not found" + +ec EXT2_ET_DIR_EXISTS, + "Ext2 directory already exists" + +ec EXT2_ET_UNIMPLEMENTED, + "Unimplemented ext2 library function" + +ec EXT2_ET_CANCEL_REQUESTED, + "User cancel requested" + +ec EXT2_ET_FILE_TOO_BIG, + "Ext2 file too big" + +ec EXT2_ET_JOURNAL_NOT_BLOCK, + "Supplied journal device not a block device" + +ec EXT2_ET_NO_JOURNAL_SB, + "Journal superblock not found" + +ec EXT2_ET_JOURNAL_TOO_SMALL, + "Journal must be at least 1024 blocks" + +ec EXT2_ET_JOURNAL_UNSUPP_VERSION, + "Unsupported journal version" + +ec EXT2_ET_LOAD_EXT_JOURNAL, + "Error loading external journal" + +ec EXT2_ET_NO_JOURNAL, + "Journal not found" + +ec EXT2_ET_DIRHASH_UNSUPP, + "Directory hash unsupported" + +ec EXT2_ET_BAD_EA_BLOCK_NUM, + "Illegal extended attribute block number" + +ec EXT2_ET_TOO_MANY_INODES, + "Cannot create filesystem with requested number of inodes" + +ec EXT2_ET_NOT_IMAGE_FILE, + "E2image snapshot not in use" + +ec EXT2_ET_RES_GDT_BLOCKS, + "Too many reserved group descriptor blocks" + +ec EXT2_ET_RESIZE_INODE_CORRUPT, + "Resize inode is corrupt" + +ec EXT2_ET_SET_BMAP_NO_IND, + "Tried to set block bmap with missing indirect block" + +ec EXT2_ET_TDB_SUCCESS, + "TDB: Success" + +ec EXT2_ET_TDB_ERR_CORRUPT, + "TDB: Corrupt database" + +ec EXT2_ET_TDB_ERR_IO, + "TDB: IO Error" + +ec EXT2_ET_TDB_ERR_LOCK, + "TDB: Locking error" + +ec EXT2_ET_TDB_ERR_OOM, + "TDB: Out of memory" + +ec EXT2_ET_TDB_ERR_EXISTS, + "TDB: Record exists" + +ec EXT2_ET_TDB_ERR_NOLOCK, + "TDB: Lock exists on other keys" + +ec EXT2_ET_TDB_ERR_EINVAL, + "TDB: Invalid parameter" + +ec EXT2_ET_TDB_ERR_NOEXIST, + "TDB: Record does not exist" + +ec EXT2_ET_TDB_ERR_RDONLY, + "TDB: Write not permitted" + +ec EXT2_ET_DBLIST_EMPTY, + "Ext2fs directory block list is empty" + +ec EXT2_ET_RO_BLOCK_ITERATE, + "Attempt to modify a block mapping via a read-only block iterator" + +ec EXT2_ET_MAGIC_EXTENT_PATH, + "Wrong magic number for ext4 extent saved path" + +ec EXT2_ET_MAGIC_GENERIC_BITMAP64, + "Wrong magic number for 64-bit generic bitmap" + +ec EXT2_ET_MAGIC_BLOCK_BITMAP64, + "Wrong magic number for 64-bit block bitmap" + +ec EXT2_ET_MAGIC_INODE_BITMAP64, + "Wrong magic number for 64-bit inode bitmap" + +ec EXT2_ET_MAGIC_RESERVED_13, + "Wrong magic number --- RESERVED_13" + +ec EXT2_ET_MAGIC_RESERVED_14, + "Wrong magic number --- RESERVED_14" + +ec EXT2_ET_MAGIC_RESERVED_15, + "Wrong magic number --- RESERVED_15" + +ec EXT2_ET_MAGIC_RESERVED_16, + "Wrong magic number --- RESERVED_16" + +ec EXT2_ET_MAGIC_RESERVED_17, + "Wrong magic number --- RESERVED_17" + +ec EXT2_ET_MAGIC_RESERVED_18, + "Wrong magic number --- RESERVED_18" + +ec EXT2_ET_MAGIC_RESERVED_19, + "Wrong magic number --- RESERVED_19" + +ec EXT2_ET_EXTENT_HEADER_BAD, + "Corrupt extent header" + +ec EXT2_ET_EXTENT_INDEX_BAD, + "Corrupt extent index" + +ec EXT2_ET_EXTENT_LEAF_BAD, + "Corrupt extent" + +ec EXT2_ET_EXTENT_NO_SPACE, + "No free space in extent map" + +ec EXT2_ET_INODE_NOT_EXTENT, + "Inode does not use extents" + +ec EXT2_ET_EXTENT_NO_NEXT, + "No 'next' extent" + +ec EXT2_ET_EXTENT_NO_PREV, + "No 'previous' extent" + +ec EXT2_ET_EXTENT_NO_UP, + "No 'up' extent" + +ec EXT2_ET_EXTENT_NO_DOWN, + "No 'down' extent" + +ec EXT2_ET_NO_CURRENT_NODE, + "No current node" + +ec EXT2_ET_OP_NOT_SUPPORTED, + "Ext2fs operation not supported" + +ec EXT2_ET_CANT_INSERT_EXTENT, + "No room to insert extent in node" + +ec EXT2_ET_CANT_SPLIT_EXTENT, + "Splitting would result in empty node" + +ec EXT2_ET_EXTENT_NOT_FOUND, + "Extent not found" + +ec EXT2_ET_EXTENT_NOT_SUPPORTED, + "Operation not supported for inodes containing extents" + +ec EXT2_ET_EXTENT_INVALID_LENGTH, + "Extent length is invalid" + +ec EXT2_ET_IO_CHANNEL_NO_SUPPORT_64, + "I/O Channel does not support 64-bit block numbers" + +ec EXT2_ET_NO_MTAB_FILE, + "Can't check if filesystem is mounted due to missing mtab file" + +ec EXT2_ET_CANT_USE_LEGACY_BITMAPS, + "Filesystem too large to use legacy bitmaps" + +ec EXT2_ET_MMP_MAGIC_INVALID, + "MMP: invalid magic number" + +ec EXT2_ET_MMP_FAILED, + "MMP: device currently active" + +ec EXT2_ET_MMP_FSCK_ON, + "MMP: e2fsck being run" + +ec EXT2_ET_MMP_BAD_BLOCK, + "MMP: block number beyond filesystem range" + +ec EXT2_ET_MMP_UNKNOWN_SEQ, + "MMP: undergoing an unknown operation" + +ec EXT2_ET_MMP_CHANGE_ABORT, + "MMP: filesystem still in use" + +ec EXT2_ET_MMP_OPEN_DIRECT, + "MMP: open with O_DIRECT failed" + +ec EXT2_ET_BAD_DESC_SIZE, + "Block group descriptor size incorrect" + +ec EXT2_ET_INODE_CSUM_INVALID, + "Inode checksum does not match inode" + +ec EXT2_ET_INODE_BITMAP_CSUM_INVALID, + "Inode bitmap checksum does not match bitmap" + +ec EXT2_ET_EXTENT_CSUM_INVALID, + "Extent block checksum does not match extent block" + +ec EXT2_ET_DIR_NO_SPACE_FOR_CSUM, + "Directory block does not have space for checksum" + +ec EXT2_ET_DIR_CSUM_INVALID, + "Directory block checksum does not match directory block" + +ec EXT2_ET_EXT_ATTR_CSUM_INVALID, + "Extended attribute block checksum does not match block" + +ec EXT2_ET_SB_CSUM_INVALID, + "Superblock checksum does not match superblock" + +ec EXT2_ET_UNKNOWN_CSUM, + "Unknown checksum algorithm" + +ec EXT2_ET_MMP_CSUM_INVALID, + "MMP block checksum does not match" + +ec EXT2_ET_FILE_EXISTS, + "Ext2 file already exists" + +ec EXT2_ET_BLOCK_BITMAP_CSUM_INVALID, + "Block bitmap checksum does not match bitmap" + +ec EXT2_ET_INLINE_DATA_CANT_ITERATE, + "Cannot iterate data blocks of an inode containing inline data" + +ec EXT2_ET_EA_BAD_NAME_LEN, + "Extended attribute has an invalid name length" + +ec EXT2_ET_EA_BAD_VALUE_SIZE, + "Extended attribute has an invalid value length" + +ec EXT2_ET_BAD_EA_HASH, + "Extended attribute has an incorrect hash" + +ec EXT2_ET_BAD_EA_HEADER, + "Extended attribute block has a bad header" + +ec EXT2_ET_EA_KEY_NOT_FOUND, + "Extended attribute key not found" + +ec EXT2_ET_EA_NO_SPACE, + "Insufficient space to store extended attribute data" + +ec EXT2_ET_MISSING_EA_FEATURE, + "Filesystem is missing ext_attr or inline_data feature" + +ec EXT2_ET_NO_INLINE_DATA, + "Inode doesn't have inline data" + +ec EXT2_ET_INLINE_DATA_NO_BLOCK, + "No block for an inode with inline data" + +ec EXT2_ET_INLINE_DATA_NO_SPACE, + "No free space in inline data" + +ec EXT2_ET_MAGIC_EA_HANDLE, + "Wrong magic number for extended attribute structure" + +ec EXT2_ET_INODE_IS_GARBAGE, + "Inode seems to contain garbage" + +ec EXT2_ET_EA_BAD_VALUE_OFFSET, + "Extended attribute has an invalid value offset" + +ec EXT2_ET_JOURNAL_FLAGS_WRONG, + "Journal flags inconsistent" + +ec EXT2_ET_UNDO_FILE_CORRUPT, + "Undo file corrupt" + +ec EXT2_ET_UNDO_FILE_WRONG, + "Wrong undo file for this filesystem" + +ec EXT2_ET_FILESYSTEM_CORRUPTED, + "File system is corrupted" + +ec EXT2_ET_BAD_CRC, + "Bad CRC detected in file system" + +ec EXT2_ET_CORRUPT_JOURNAL_SB, + "The journal superblock is corrupt" + +ec EXT2_ET_INODE_CORRUPTED, + "Inode is corrupted" + +ec EXT2_ET_EA_INODE_CORRUPTED, + "Inode containing extended attribute value is corrupted" + + end diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/ext2_types.h.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/ext2_types.h.in Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,196 @@ +/* + * If linux/types.h is already been included, assume it has defined + * everything we need. (cross fingers) Other header files may have + * also defined the types that we need. + */ +#if (!defined(_LINUX_TYPES_H) && !defined(_BLKID_TYPES_H) && \ + !defined(_EXT2_TYPES_H)) +#define _EXT2_TYPES_H + +@ASM_TYPES_HEADER@ + +#ifndef HAVE___U8 +#define HAVE___U8 +#ifdef __U8_TYPEDEF +typedef __U8_TYPEDEF __u8; +#else +typedef unsigned char __u8; +#endif +#endif /* HAVE___U8 */ + +#ifndef HAVE___S8 +#define HAVE___S8 +#ifdef __S8_TYPEDEF +typedef __S8_TYPEDEF __s8; +#else +typedef signed char __s8; +#endif +#endif /* HAVE___S8 */ + +#ifndef HAVE___U16 +#define HAVE___U16 +#ifdef __U16_TYPEDEF +typedef __U16_TYPEDEF __u16; +#else +#if (@SIZEOF_INT@ == 2) +typedef unsigned int __u16; +#else +#if (@SIZEOF_SHORT@ == 2) +typedef unsigned short __u16; +#else +#undef HAVE___U16 + ?==error: undefined 16 bit type +#endif /* SIZEOF_SHORT == 2 */ +#endif /* SIZEOF_INT == 2 */ +#endif /* __U16_TYPEDEF */ +#endif /* HAVE___U16 */ + +#ifndef HAVE___S16 +#define HAVE___S16 +#ifdef __S16_TYPEDEF +typedef __S16_TYPEDEF __s16; +#else +#if (@SIZEOF_INT@ == 2) +typedef int __s16; +#else +#if (@SIZEOF_SHORT@ == 2) +typedef short __s16; +#else +#undef HAVE___S16 + ?==error: undefined 16 bit type +#endif /* SIZEOF_SHORT == 2 */ +#endif /* SIZEOF_INT == 2 */ +#endif /* __S16_TYPEDEF */ +#endif /* HAVE___S16 */ + +#ifndef HAVE___U32 +#define HAVE___U32 +#ifdef __U32_TYPEDEF +typedef __U32_TYPEDEF __u32; +#else +#if (@SIZEOF_INT@ == 4) +typedef unsigned int __u32; +#else +#if (@SIZEOF_LONG@ == 4) +typedef unsigned long __u32; +#else +#if (@SIZEOF_SHORT@ == 4) +typedef unsigned short __u32; +#else +#undef HAVE___U32 + ?== error: undefined 32 bit type +#endif /* SIZEOF_SHORT == 4 */ +#endif /* SIZEOF_LONG == 4 */ +#endif /* SIZEOF_INT == 4 */ +#endif /* __U32_TYPEDEF */ +#endif /* HAVE___U32 */ + +#ifndef HAVE___S32 +#define HAVE___S32 +#ifdef __S32_TYPEDEF +typedef __S32_TYPEDEF __s32; +#else +#if (@SIZEOF_INT@ == 4) +typedef int __s32; +#else +#if (@SIZEOF_LONG@ == 4) +typedef long __s32; +#else +#if (@SIZEOF_SHORT@ == 4) +typedef short __s32; +#else +#undef HAVE___S32 + ?== error: undefined 32 bit type +#endif /* SIZEOF_SHORT == 4 */ +#endif /* SIZEOF_LONG == 4 */ +#endif /* SIZEOF_INT == 4 */ +#endif /* __S32_TYPEDEF */ +#endif /* HAVE___S32 */ + +#ifndef HAVE___U64 +#define HAVE___U64 +#ifdef __U64_TYPEDEF +typedef __U64_TYPEDEF __u64; +#else +#if (@SIZEOF_INT@ == 8) +typedef unsigned int __u64; +#else +#if (@SIZEOF_LONG_LONG@ == 8) +typedef unsigned long long __u64; +#else +#if (@SIZEOF_LONG@ == 8) +typedef unsigned long __u64; +#else +#undef HAVE___U64 + ?== error: undefined 64 bit type +#endif /* SIZEOF_LONG_LONG == 8 */ +#endif /* SIZEOF_LONG == 8 */ +#endif /* SIZEOF_INT == 8 */ +#endif /* __U64_TYPEDEF */ +#endif /* HAVE___U64 */ + +#ifndef HAVE___S64 +#define HAVE___S64 +#ifdef __S64_TYPEDEF +typedef __S64_TYPEDEF __s64; +#else +#if (@SIZEOF_INT@ == 8) +typedef int __s64; +#else +#if (@SIZEOF_LONG_LONG@ == 8) +#if defined(__GNUC__) +typedef __signed__ long long __s64; +#else +typedef signed long long __s64; +#endif /* __GNUC__ */ +#else +#if (@SIZEOF_LONG@ == 8) +typedef long __s64; +#else +#undef HAVE___S64 + ?== error: undefined 64 bit type +#endif /* SIZEOF_LONG_LONG == 8 */ +#endif /* SIZEOF_LONG == 8 */ +#endif /* SIZEOF_INT == 8 */ +#endif /* __S64_TYPEDEF */ +#endif /* HAVE___S64 */ + +#undef __S8_TYPEDEF +#undef __U8_TYPEDEF +#undef __S16_TYPEDEF +#undef __U16_TYPEDEF +#undef __S32_TYPEDEF +#undef __U32_TYPEDEF +#undef __S64_TYPEDEF +#undef __U64_TYPEDEF + +#endif /* _*_TYPES_H */ + +#include + +/* endian checking stuff */ +#ifndef EXT2_ENDIAN_H_ +#define EXT2_ENDIAN_H_ + +#ifdef __CHECKER__ +# ifndef __bitwise +# define __bitwise __attribute__((bitwise)) +# endif +#define __force __attribute__((force)) +#else +# ifndef __bitwise +# define __bitwise +# endif +#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; + +#endif /* EXT2_ENDIAN_H_ */ + +@PUBLIC_CONFIG_HEADER@ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/ext2fs.pc.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/ext2fs.pc.in Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ext2fs +Description: Ext2fs library +Version: @E2FSPROGS_VERSION@ +Requires.private: com_err +Cflags: -I${includedir}/ext2fs -I${includedir} +Libs: -L${libdir} -lext2fs diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/ext_attr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/ext_attr.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,1718 @@ +/* + * ext_attr.c --- extended attribute blocks + * + * Copyright (C) 2001 Andreas Gruenbacher, + * + * Copyright (C) 2002 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "ext2_fs.h" +#include "ext2_ext_attr.h" +#include "ext4_acl.h" + +#include "ext2fs.h" + +static errcode_t read_ea_inode_hash(ext2_filsys fs, ext2_ino_t ino, __u32 *hash) +{ + struct ext2_inode inode; + errcode_t retval; + + retval = ext2fs_read_inode(fs, ino, &inode); + if (retval) + return retval; + *hash = ext2fs_get_ea_inode_hash(&inode); + return 0; +} + +#define NAME_HASH_SHIFT 5 +#define VALUE_HASH_SHIFT 16 + +/* + * ext2_xattr_hash_entry() + * + * Compute the hash of an extended attribute. + */ +__u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data) +{ + __u32 hash = 0; + char *name = ((char *) entry) + sizeof(struct ext2_ext_attr_entry); + int n; + + for (n = 0; n < entry->e_name_len; n++) { + hash = (hash << NAME_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ + *name++; + } + + /* The hash needs to be calculated on the data in little-endian. */ + if (entry->e_value_inum == 0 && entry->e_value_size != 0) { + __u32 *value = (__u32 *)data; + for (n = (entry->e_value_size + EXT2_EXT_ATTR_ROUND) >> + EXT2_EXT_ATTR_PAD_BITS; n; n--) { + hash = (hash << VALUE_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ + ext2fs_le32_to_cpu(*value++); + } + } + + return hash; +} + +/* + * ext2fs_ext_attr_hash_entry2() + * + * Compute the hash of an extended attribute. + * This version of the function supports hashing entries that reference + * external inodes (ea_inode feature). + */ +errcode_t ext2fs_ext_attr_hash_entry2(ext2_filsys fs, + struct ext2_ext_attr_entry *entry, + void *data, __u32 *hash) +{ + *hash = ext2fs_ext_attr_hash_entry(entry, data); + + if (entry->e_value_inum) { + __u32 ea_inode_hash; + errcode_t retval; + + retval = read_ea_inode_hash(fs, entry->e_value_inum, + &ea_inode_hash); + if (retval) + return retval; + + *hash = (*hash << VALUE_HASH_SHIFT) ^ + (*hash >> (8*sizeof(*hash) - VALUE_HASH_SHIFT)) ^ + ea_inode_hash; + } + return 0; +} + +#undef NAME_HASH_SHIFT +#undef VALUE_HASH_SHIFT + +#define BLOCK_HASH_SHIFT 16 + +/* Mirrors ext4_xattr_rehash() implementation in kernel. */ +void ext2fs_ext_attr_block_rehash(struct ext2_ext_attr_header *header, + struct ext2_ext_attr_entry *end) +{ + struct ext2_ext_attr_entry *here; + __u32 hash = 0; + + here = (struct ext2_ext_attr_entry *)(header+1); + while (here < end && !EXT2_EXT_IS_LAST_ENTRY(here)) { + if (!here->e_hash) { + /* Block is not shared if an entry's hash value == 0 */ + hash = 0; + break; + } + hash = (hash << BLOCK_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^ + here->e_hash; + here = EXT2_EXT_ATTR_NEXT(here); + } + header->h_hash = hash; +} + +#undef BLOCK_HASH_SHIFT + +__u32 ext2fs_get_ea_inode_hash(struct ext2_inode *inode) +{ + return inode->i_atime; +} + +void ext2fs_set_ea_inode_hash(struct ext2_inode *inode, __u32 hash) +{ + inode->i_atime = hash; +} + +__u64 ext2fs_get_ea_inode_ref(struct ext2_inode *inode) +{ + return ((__u64)inode->i_ctime << 32) | inode->osd1.linux1.l_i_version; +} + +void ext2fs_set_ea_inode_ref(struct ext2_inode *inode, __u64 ref_count) +{ + inode->i_ctime = (__u32)(ref_count >> 32); + inode->osd1.linux1.l_i_version = (__u32)ref_count; +} + +static errcode_t check_ext_attr_header(struct ext2_ext_attr_header *header) +{ + if ((header->h_magic != EXT2_EXT_ATTR_MAGIC_v1 && + header->h_magic != EXT2_EXT_ATTR_MAGIC) || + header->h_blocks != 1) + return EXT2_ET_BAD_EA_HEADER; + + return 0; +} + +errcode_t ext2fs_read_ext_attr3(ext2_filsys fs, blk64_t block, void *buf, + ext2_ino_t inum) +{ + int csum_failed = 0; + errcode_t retval; + + retval = io_channel_read_blk64(fs->io, block, 1, buf); + if (retval) + return retval; + + if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_ext_attr_block_csum_verify(fs, inum, block, buf)) + csum_failed = 1; + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1); +#endif + + retval = check_ext_attr_header(buf); + if (retval == 0 && csum_failed) + retval = EXT2_ET_EXT_ATTR_CSUM_INVALID; + + return retval; +} + +errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block, void *buf) +{ + return ext2fs_read_ext_attr3(fs, block, buf, 0); +} + +errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf) +{ + return ext2fs_read_ext_attr2(fs, block, buf); +} + +errcode_t ext2fs_write_ext_attr3(ext2_filsys fs, blk64_t block, void *inbuf, + ext2_ino_t inum) +{ + errcode_t retval; + char *write_buf; + +#ifdef WORDS_BIGENDIAN + retval = ext2fs_get_mem(fs->blocksize, &write_buf); + if (retval) + return retval; + ext2fs_swap_ext_attr(write_buf, inbuf, fs->blocksize, 1); +#else + write_buf = (char *) inbuf; +#endif + + retval = ext2fs_ext_attr_block_csum_set(fs, inum, block, + (struct ext2_ext_attr_header *)write_buf); + if (retval) + return retval; + + retval = io_channel_write_blk64(fs->io, block, 1, write_buf); +#ifdef WORDS_BIGENDIAN + ext2fs_free_mem(&write_buf); +#endif + if (!retval) + ext2fs_mark_changed(fs); + return retval; +} + +errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block, void *inbuf) +{ + return ext2fs_write_ext_attr3(fs, block, inbuf, 0); +} + +errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf) +{ + return ext2fs_write_ext_attr2(fs, block, inbuf); +} + +/* + * This function adjusts the reference count of the EA block. + */ +errcode_t ext2fs_adjust_ea_refcount3(ext2_filsys fs, blk64_t blk, + char *block_buf, int adjust, + __u32 *newcount, ext2_ino_t inum) +{ + errcode_t retval; + struct ext2_ext_attr_header *header; + char *buf = 0; + + if ((blk >= ext2fs_blocks_count(fs->super)) || + (blk < fs->super->s_first_data_block)) + return EXT2_ET_BAD_EA_BLOCK_NUM; + + if (!block_buf) { + retval = ext2fs_get_mem(fs->blocksize, &buf); + if (retval) + return retval; + block_buf = buf; + } + + retval = ext2fs_read_ext_attr3(fs, blk, block_buf, inum); + if (retval) + goto errout; + + header = (struct ext2_ext_attr_header *) block_buf; + header->h_refcount += adjust; + if (newcount) + *newcount = header->h_refcount; + + retval = ext2fs_write_ext_attr3(fs, blk, block_buf, inum); + if (retval) + goto errout; + +errout: + if (buf) + ext2fs_free_mem(&buf); + return retval; +} + +errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk, + char *block_buf, int adjust, + __u32 *newcount) +{ + return ext2fs_adjust_ea_refcount3(fs, blk, block_buf, adjust, + newcount, 0); +} + +errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk, + char *block_buf, int adjust, + __u32 *newcount) +{ + return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust, + newcount); +} + +/* Manipulate the contents of extended attribute regions */ +struct ext2_xattr { + char *name; + void *value; + unsigned int value_len; + ext2_ino_t ea_ino; +}; + +struct ext2_xattr_handle { + errcode_t magic; + ext2_filsys fs; + struct ext2_xattr *attrs; + int capacity; + int count; + int ibody_count; + ext2_ino_t ino; + unsigned int flags; +}; + +static errcode_t ext2fs_xattrs_expand(struct ext2_xattr_handle *h, + unsigned int expandby) +{ + struct ext2_xattr *new_attrs; + errcode_t err; + + err = ext2fs_get_arrayzero(h->capacity + expandby, + sizeof(struct ext2_xattr), &new_attrs); + if (err) + return err; + + memcpy(new_attrs, h->attrs, h->capacity * sizeof(struct ext2_xattr)); + ext2fs_free_mem(&h->attrs); + h->capacity += expandby; + h->attrs = new_attrs; + + return 0; +} + +struct ea_name_index { + int index; + const char *name; +}; + +/* Keep these names sorted in order of decreasing specificity. */ +static struct ea_name_index ea_names[] = { + {3, "system.posix_acl_default"}, + {2, "system.posix_acl_access"}, + {8, "system.richacl"}, + {6, "security."}, + {4, "trusted."}, + {7, "system."}, + {1, "user."}, + {0, NULL}, +}; + +static const char *find_ea_prefix(int index) +{ + struct ea_name_index *e; + + for (e = ea_names; e->name; e++) + if (e->index == index) + return e->name; + + return NULL; +} + +static int find_ea_index(const char *fullname, const char **name, int *index) +{ + struct ea_name_index *e; + + for (e = ea_names; e->name; e++) { + if (strncmp(fullname, e->name, strlen(e->name)) == 0) { + *name = fullname + strlen(e->name); + *index = e->index; + return 1; + } + } + return 0; +} + +errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode_large *inode) +{ + struct ext2_ext_attr_header *header; + void *block_buf = NULL; + blk64_t blk; + errcode_t err; + struct ext2_inode_large i; + + /* Read inode? */ + if (inode == NULL) { + err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&i, + sizeof(struct ext2_inode_large)); + if (err) + return err; + inode = &i; + } + + /* Do we already have an EA block? */ + blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode); + if (blk == 0) + return 0; + + /* Find block, zero it, write back */ + if ((blk < fs->super->s_first_data_block) || + (blk >= ext2fs_blocks_count(fs->super))) { + err = EXT2_ET_BAD_EA_BLOCK_NUM; + goto out; + } + + err = ext2fs_get_mem(fs->blocksize, &block_buf); + if (err) + goto out; + + err = ext2fs_read_ext_attr3(fs, blk, block_buf, ino); + if (err) + goto out2; + + /* We only know how to deal with v2 EA blocks */ + header = (struct ext2_ext_attr_header *) block_buf; + if (header->h_magic != EXT2_EXT_ATTR_MAGIC) { + err = EXT2_ET_BAD_EA_HEADER; + goto out2; + } + + header->h_refcount--; + err = ext2fs_write_ext_attr3(fs, blk, block_buf, ino); + if (err) + goto out2; + + /* Erase link to block */ + ext2fs_file_acl_block_set(fs, (struct ext2_inode *)inode, 0); + if (header->h_refcount == 0) + ext2fs_block_alloc_stats2(fs, blk, -1); + err = ext2fs_iblk_sub_blocks(fs, (struct ext2_inode *)inode, 1); + if (err) + goto out2; + + /* Write inode? */ + if (inode == &i) { + err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&i, + sizeof(struct ext2_inode_large)); + if (err) + goto out2; + } + +out2: + ext2fs_free_mem(&block_buf); +out: + return err; +} + +static errcode_t prep_ea_block_for_write(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode_large *inode) +{ + struct ext2_ext_attr_header *header; + void *block_buf = NULL; + blk64_t blk, goal; + errcode_t err; + + /* Do we already have an EA block? */ + blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode); + if (blk != 0) { + if ((blk < fs->super->s_first_data_block) || + (blk >= ext2fs_blocks_count(fs->super))) { + err = EXT2_ET_BAD_EA_BLOCK_NUM; + goto out; + } + + err = ext2fs_get_mem(fs->blocksize, &block_buf); + if (err) + goto out; + + err = ext2fs_read_ext_attr3(fs, blk, block_buf, ino); + if (err) + goto out2; + + /* We only know how to deal with v2 EA blocks */ + header = (struct ext2_ext_attr_header *) block_buf; + if (header->h_magic != EXT2_EXT_ATTR_MAGIC) { + err = EXT2_ET_BAD_EA_HEADER; + goto out2; + } + + /* Single-user block. We're done here. */ + if (header->h_refcount == 1) + goto out2; + + /* We need to CoW the block. */ + header->h_refcount--; + err = ext2fs_write_ext_attr3(fs, blk, block_buf, ino); + if (err) + goto out2; + } else { + /* No block, we must increment i_blocks */ + err = ext2fs_iblk_add_blocks(fs, (struct ext2_inode *)inode, + 1); + if (err) + goto out; + } + + /* Allocate a block */ + goal = ext2fs_find_inode_goal(fs, ino, (struct ext2_inode *)inode, 0); + err = ext2fs_alloc_block2(fs, goal, NULL, &blk); + if (err) + goto out2; + ext2fs_file_acl_block_set(fs, (struct ext2_inode *)inode, blk); +out2: + if (block_buf) + ext2fs_free_mem(&block_buf); +out: + return err; +} + + +static inline int +posix_acl_xattr_count(size_t size) +{ + if (size < sizeof(posix_acl_xattr_header)) + return -1; + size -= sizeof(posix_acl_xattr_header); + if (size % sizeof(posix_acl_xattr_entry)) + return -1; + return size / sizeof(posix_acl_xattr_entry); +} + +/* + * The lgetxattr function returns data formatted in the POSIX extended + * attribute format. The on-disk format uses a more compact encoding. + * See the ext4_acl_to_disk in fs/ext4/acl.c. + */ +static errcode_t convert_posix_acl_to_disk_buffer(const void *value, size_t size, + void *out_buf, size_t *size_out) +{ + const posix_acl_xattr_header *header = + (const posix_acl_xattr_header*) value; + const posix_acl_xattr_entry *end, *entry = + (const posix_acl_xattr_entry *)(header+1); + ext4_acl_header *ext_acl; + size_t s; + char *e; + + int count; + + if (!value) + return EINVAL; + if (size < sizeof(posix_acl_xattr_header)) + return ENOMEM; + if (header->a_version != ext2fs_cpu_to_le32(POSIX_ACL_XATTR_VERSION)) + return EINVAL; + + count = posix_acl_xattr_count(size); + ext_acl = out_buf; + ext_acl->a_version = ext2fs_cpu_to_le32(EXT4_ACL_VERSION); + + if (count <= 0) + return EINVAL; + + e = (char *) out_buf + sizeof(ext4_acl_header); + s = sizeof(ext4_acl_header); + for (end = entry + count; entry != end;entry++) { + ext4_acl_entry *disk_entry = (ext4_acl_entry*) e; + disk_entry->e_tag = ext2fs_cpu_to_le16(entry->e_tag); + disk_entry->e_perm = ext2fs_cpu_to_le16(entry->e_perm); + + switch(entry->e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + e += sizeof(ext4_acl_entry_short); + s += sizeof(ext4_acl_entry_short); + break; + case ACL_USER: + case ACL_GROUP: + disk_entry->e_id = ext2fs_cpu_to_le32(entry->e_id); + e += sizeof(ext4_acl_entry); + s += sizeof(ext4_acl_entry); + break; + } + } + *size_out = s; + return 0; +} + +static errcode_t convert_disk_buffer_to_posix_acl(const void *value, size_t size, + void **out_buf, size_t *size_out) +{ + posix_acl_xattr_header *header; + posix_acl_xattr_entry *entry; + const ext4_acl_header *ext_acl = (const ext4_acl_header *) value; + errcode_t err; + const char *cp; + char *out; + + if ((!value) || + (size < sizeof(ext4_acl_header)) || + (ext_acl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION))) + return EINVAL; + + err = ext2fs_get_mem(size * 2, &out); + if (err) + return err; + + header = (posix_acl_xattr_header *) out; + header->a_version = ext2fs_cpu_to_le32(POSIX_ACL_XATTR_VERSION); + entry = (posix_acl_xattr_entry *) (out + sizeof(posix_acl_xattr_header)); + + cp = (const char *) value + sizeof(ext4_acl_header); + size -= sizeof(ext4_acl_header); + + while (size > 0) { + const ext4_acl_entry *disk_entry = (const ext4_acl_entry *) cp; + + entry->e_tag = ext2fs_le16_to_cpu(disk_entry->e_tag); + entry->e_perm = ext2fs_le16_to_cpu(disk_entry->e_perm); + + switch(entry->e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + entry->e_id = 0; + cp += sizeof(ext4_acl_entry_short); + size -= sizeof(ext4_acl_entry_short); + break; + case ACL_USER: + case ACL_GROUP: + entry->e_id = ext2fs_le32_to_cpu(disk_entry->e_id); + cp += sizeof(ext4_acl_entry); + size -= sizeof(ext4_acl_entry); + break; + default: + ext2fs_free_mem(&out); + return EINVAL; + break; + } + entry++; + } + *out_buf = out; + *size_out = ((char *) entry - out); + return 0; +} + +static errcode_t +write_xattrs_to_buffer(ext2_filsys fs, struct ext2_xattr *attrs, int count, + void *entries_start, unsigned int storage_size, + unsigned int value_offset_correction, int write_hash) +{ + struct ext2_xattr *x; + struct ext2_ext_attr_entry *e = entries_start; + char *end = (char *) entries_start + storage_size; + const char *shortname; + unsigned int value_size; + int idx, ret; + errcode_t err; + + memset(entries_start, 0, storage_size); + for (x = attrs; x < attrs + count; x++) { + /* Calculate index and shortname position */ + shortname = x->name; + ret = find_ea_index(x->name, &shortname, &idx); + + value_size = ((x->value_len + EXT2_EXT_ATTR_PAD - 1) / + EXT2_EXT_ATTR_PAD) * EXT2_EXT_ATTR_PAD; + + /* Fill out e appropriately */ + e->e_name_len = strlen(shortname); + e->e_name_index = (ret ? idx : 0); + + e->e_value_size = x->value_len; + e->e_value_inum = x->ea_ino; + + /* Store name */ + memcpy((char *)e + sizeof(*e), shortname, e->e_name_len); + if (x->ea_ino) { + e->e_value_offs = 0; + } else { + end -= value_size; + e->e_value_offs = end - (char *) entries_start + + value_offset_correction; + memcpy(end, x->value, e->e_value_size); + } + + if (write_hash || x->ea_ino) { + err = ext2fs_ext_attr_hash_entry2(fs, e, + x->ea_ino ? 0 : end, + &e->e_hash); + if (err) + return err; + } else + e->e_hash = 0; + + e = EXT2_EXT_ATTR_NEXT(e); + *(__u32 *)e = 0; + } + return 0; +} + +errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle) +{ + ext2_filsys fs = handle->fs; + const unsigned int inode_size = EXT2_INODE_SIZE(fs->super); + struct ext2_inode_large *inode; + char *start, *block_buf = NULL; + struct ext2_ext_attr_header *header; + __u32 ea_inode_magic; + blk64_t blk; + unsigned int storage_size; + unsigned int i; + errcode_t err; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE); + i = inode_size; + if (i < sizeof(*inode)) + i = sizeof(*inode); + err = ext2fs_get_memzero(i, &inode); + if (err) + return err; + + err = ext2fs_read_inode_full(fs, handle->ino, EXT2_INODE(inode), + inode_size); + if (err) + goto out; + + /* If extra_isize isn't set, we need to set it now */ + if (inode->i_extra_isize == 0 && + inode_size > EXT2_GOOD_OLD_INODE_SIZE) { + char *p = (char *)inode; + size_t extra = fs->super->s_want_extra_isize; + + if (extra == 0) + extra = sizeof(__u32); + memset(p + EXT2_GOOD_OLD_INODE_SIZE, 0, extra); + inode->i_extra_isize = extra; + } + if (inode->i_extra_isize & 3) { + err = EXT2_ET_INODE_CORRUPTED; + goto out; + } + + /* Does the inode have space for EA? */ + if (inode->i_extra_isize < sizeof(inode->i_extra_isize) || + inode_size <= EXT2_GOOD_OLD_INODE_SIZE + inode->i_extra_isize + + sizeof(__u32)) + goto write_ea_block; + + /* Write the inode EA */ + ea_inode_magic = EXT2_EXT_ATTR_MAGIC; + memcpy(((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize, &ea_inode_magic, sizeof(__u32)); + storage_size = inode_size - EXT2_GOOD_OLD_INODE_SIZE - + inode->i_extra_isize - sizeof(__u32); + start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize + sizeof(__u32); + + err = write_xattrs_to_buffer(fs, handle->attrs, handle->ibody_count, + start, storage_size, 0, 0); + if (err) + goto out; +write_ea_block: + /* Are we done? */ + if (handle->ibody_count == handle->count && + !ext2fs_file_acl_block(fs, EXT2_INODE(inode))) + goto skip_ea_block; + + /* Write the EA block */ + err = ext2fs_get_memzero(fs->blocksize, &block_buf); + if (err) + goto out; + + storage_size = fs->blocksize - sizeof(struct ext2_ext_attr_header); + start = block_buf + sizeof(struct ext2_ext_attr_header); + + err = write_xattrs_to_buffer(fs, handle->attrs + handle->ibody_count, + handle->count - handle->ibody_count, start, + storage_size, start - block_buf, 1); + if (err) + goto out2; + + /* Write a header on the EA block */ + header = (struct ext2_ext_attr_header *) block_buf; + header->h_magic = EXT2_EXT_ATTR_MAGIC; + header->h_refcount = 1; + header->h_blocks = 1; + + /* Get a new block for writing */ + err = prep_ea_block_for_write(fs, handle->ino, inode); + if (err) + goto out2; + + /* Finally, write the new EA block */ + blk = ext2fs_file_acl_block(fs, EXT2_INODE(inode)); + err = ext2fs_write_ext_attr3(fs, blk, block_buf, handle->ino); + if (err) + goto out2; + +skip_ea_block: + blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode); + if (!block_buf && blk) { + /* xattrs shrunk, free the block */ + err = ext2fs_free_ext_attr(fs, handle->ino, inode); + if (err) + goto out; + } + + /* Write the inode */ + err = ext2fs_write_inode_full(fs, handle->ino, EXT2_INODE(inode), + inode_size); + if (err) + goto out2; + +out2: + ext2fs_free_mem(&block_buf); +out: + ext2fs_free_mem(&inode); + return err; +} + +static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle, + struct ext2_inode_large *inode, + struct ext2_ext_attr_entry *entries, + unsigned int storage_size, + char *value_start) +{ + struct ext2_xattr *x; + struct ext2_ext_attr_entry *entry, *end; + const char *prefix; + unsigned int remain, prefix_len; + errcode_t err; + unsigned int values_size = storage_size + + ((char *)entries - value_start); + + /* find the end */ + end = entries; + remain = storage_size; + while (remain >= sizeof(struct ext2_ext_attr_entry) && + !EXT2_EXT_IS_LAST_ENTRY(end)) { + + /* header eats this space */ + remain -= sizeof(struct ext2_ext_attr_entry); + + /* is attribute name valid? */ + if (EXT2_EXT_ATTR_SIZE(end->e_name_len) > remain) + return EXT2_ET_EA_BAD_NAME_LEN; + + /* attribute len eats this space */ + remain -= EXT2_EXT_ATTR_SIZE(end->e_name_len); + end = EXT2_EXT_ATTR_NEXT(end); + } + + entry = entries; + remain = storage_size; + while (remain >= sizeof(struct ext2_ext_attr_entry) && + !EXT2_EXT_IS_LAST_ENTRY(entry)) { + + /* Allocate space for more attrs? */ + if (handle->count == handle->capacity) { + err = ext2fs_xattrs_expand(handle, 4); + if (err) + return err; + } + + x = handle->attrs + handle->count; + + /* header eats this space */ + remain -= sizeof(struct ext2_ext_attr_entry); + + /* attribute len eats this space */ + remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len); + + /* Extract name */ + prefix = find_ea_prefix(entry->e_name_index); + prefix_len = (prefix ? strlen(prefix) : 0); + err = ext2fs_get_memzero(entry->e_name_len + prefix_len + 1, + &x->name); + if (err) + return err; + if (prefix) + memcpy(x->name, prefix, prefix_len); + if (entry->e_name_len) + memcpy(x->name + prefix_len, + (char *)entry + sizeof(*entry), + entry->e_name_len); + + /* Check & copy value */ + if (!ext2fs_has_feature_ea_inode(handle->fs->super) && + entry->e_value_inum != 0) + return EXT2_ET_BAD_EA_BLOCK_NUM; + + if (entry->e_value_inum == 0) { + if (entry->e_value_size > remain) + return EXT2_ET_EA_BAD_VALUE_SIZE; + + if (entry->e_value_offs + entry->e_value_size > values_size) + return EXT2_ET_EA_BAD_VALUE_OFFSET; + + if (entry->e_value_size > 0 && + value_start + entry->e_value_offs < + (char *)end + sizeof(__u32)) + return EXT2_ET_EA_BAD_VALUE_OFFSET; + + remain -= entry->e_value_size; + + err = ext2fs_get_mem(entry->e_value_size, &x->value); + if (err) + return err; + memcpy(x->value, value_start + entry->e_value_offs, + entry->e_value_size); + } else { + struct ext2_inode *ea_inode; + ext2_file_t ea_file; + + if (entry->e_value_offs != 0) + return EXT2_ET_EA_BAD_VALUE_OFFSET; + + if (entry->e_value_size > (64 * 1024)) + return EXT2_ET_EA_BAD_VALUE_SIZE; + + err = ext2fs_get_mem(entry->e_value_size, &x->value); + if (err) + return err; + + err = ext2fs_file_open(handle->fs, entry->e_value_inum, + 0, &ea_file); + if (err) + return err; + + ea_inode = ext2fs_file_get_inode(ea_file); + if ((ea_inode->i_flags & EXT4_INLINE_DATA_FL) || + !(ea_inode->i_flags & EXT4_EA_INODE_FL) || + ea_inode->i_links_count == 0) + err = EXT2_ET_EA_INODE_CORRUPTED; + else if (ext2fs_file_get_size(ea_file) != + entry->e_value_size) + err = EXT2_ET_EA_BAD_VALUE_SIZE; + else + err = ext2fs_file_read(ea_file, x->value, + entry->e_value_size, 0); + ext2fs_file_close(ea_file); + if (err) + return err; + } + + x->ea_ino = entry->e_value_inum; + x->value_len = entry->e_value_size; + + /* e_hash may be 0 in older inode's ea */ + if (entry->e_hash != 0) { + __u32 hash; + void *data = (entry->e_value_inum != 0) ? + 0 : value_start + entry->e_value_offs; + + err = ext2fs_ext_attr_hash_entry2(handle->fs, entry, + data, &hash); + if (err) + return err; + if (entry->e_hash != hash) { + struct ext2_inode child; + + /* Check whether this is an old Lustre-style + * ea_inode reference. + */ + err = ext2fs_read_inode(handle->fs, + entry->e_value_inum, + &child); + if (err) + return err; + if (child.i_mtime != handle->ino || + child.i_generation != inode->i_generation) + return EXT2_ET_BAD_EA_HASH; + } + } + + handle->count++; + entry = EXT2_EXT_ATTR_NEXT(entry); + } + + return 0; +} + +static void xattrs_free_keys(struct ext2_xattr_handle *h) +{ + struct ext2_xattr *a = h->attrs; + int i; + + for (i = 0; i < h->capacity; i++) { + if (a[i].name) + ext2fs_free_mem(&a[i].name); + if (a[i].value) + ext2fs_free_mem(&a[i].value); + } + h->count = 0; + h->ibody_count = 0; +} + +errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle) +{ + struct ext2_inode_large *inode; + struct ext2_ext_attr_header *header; + __u32 ea_inode_magic; + unsigned int storage_size; + char *start, *block_buf = NULL; + blk64_t blk; + size_t i; + errcode_t err; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE); + i = EXT2_INODE_SIZE(handle->fs->super); + if (i < sizeof(*inode)) + i = sizeof(*inode); + err = ext2fs_get_memzero(i, &inode); + if (err) + return err; + + err = ext2fs_read_inode_full(handle->fs, handle->ino, + (struct ext2_inode *)inode, + EXT2_INODE_SIZE(handle->fs->super)); + if (err) + goto out; + + xattrs_free_keys(handle); + + /* Does the inode have space for EA? */ + if (inode->i_extra_isize < sizeof(inode->i_extra_isize) || + EXT2_INODE_SIZE(handle->fs->super) <= EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize + + sizeof(__u32)) + goto read_ea_block; + if (inode->i_extra_isize & 3) { + err = EXT2_ET_INODE_CORRUPTED; + goto out; + } + + /* Look for EA in the inode */ + memcpy(&ea_inode_magic, ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize, sizeof(__u32)); + if (ea_inode_magic == EXT2_EXT_ATTR_MAGIC) { + storage_size = EXT2_INODE_SIZE(handle->fs->super) - + EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize - + sizeof(__u32); + start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize + sizeof(__u32); + + err = read_xattrs_from_buffer(handle, inode, + (struct ext2_ext_attr_entry *) start, + storage_size, start); + if (err) + goto out; + + handle->ibody_count = handle->count; + } + +read_ea_block: + /* Look for EA in a separate EA block */ + blk = ext2fs_file_acl_block(handle->fs, (struct ext2_inode *)inode); + if (blk != 0) { + if ((blk < handle->fs->super->s_first_data_block) || + (blk >= ext2fs_blocks_count(handle->fs->super))) { + err = EXT2_ET_BAD_EA_BLOCK_NUM; + goto out; + } + + err = ext2fs_get_mem(handle->fs->blocksize, &block_buf); + if (err) + goto out; + + err = ext2fs_read_ext_attr3(handle->fs, blk, block_buf, + handle->ino); + if (err) + goto out3; + + /* We only know how to deal with v2 EA blocks */ + header = (struct ext2_ext_attr_header *) block_buf; + if (header->h_magic != EXT2_EXT_ATTR_MAGIC) { + err = EXT2_ET_BAD_EA_HEADER; + goto out3; + } + + /* Read EAs */ + storage_size = handle->fs->blocksize - + sizeof(struct ext2_ext_attr_header); + start = block_buf + sizeof(struct ext2_ext_attr_header); + err = read_xattrs_from_buffer(handle, inode, + (struct ext2_ext_attr_entry *) start, + storage_size, block_buf); + if (err) + goto out3; + + ext2fs_free_mem(&block_buf); + } + + ext2fs_free_mem(&block_buf); + ext2fs_free_mem(&inode); + return 0; + +out3: + ext2fs_free_mem(&block_buf); +out: + ext2fs_free_mem(&inode); + return err; +} + +errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h, + int (*func)(char *name, char *value, + size_t value_len, void *data), + void *data) +{ + struct ext2_xattr *x; + int dirty = 0; + int ret; + + EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE); + for (x = h->attrs; x < h->attrs + h->count; x++) { + ret = func(x->name, x->value, x->value_len, data); + if (ret & XATTR_CHANGED) + dirty = 1; + if (ret & XATTR_ABORT) + break; + } + + if (dirty) + return ext2fs_xattrs_write(h); + return 0; +} + +errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key, + void **value, size_t *value_len) +{ + struct ext2_xattr *x; + char *val; + errcode_t err; + + EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE); + for (x = h->attrs; x < h->attrs + h->count; x++) { + if (strcmp(x->name, key)) + continue; + + if (!(h->flags & XATTR_HANDLE_FLAG_RAW) && + ((strcmp(key, "system.posix_acl_default") == 0) || + (strcmp(key, "system.posix_acl_access") == 0))) { + err = convert_disk_buffer_to_posix_acl(x->value, x->value_len, + value, value_len); + return err; + } else { + err = ext2fs_get_mem(x->value_len, &val); + if (err) + return err; + memcpy(val, x->value, x->value_len); + *value = val; + *value_len = x->value_len; + return 0; + } + } + + return EXT2_ET_EA_KEY_NOT_FOUND; +} + +errcode_t ext2fs_xattr_inode_max_size(ext2_filsys fs, ext2_ino_t ino, + size_t *size) +{ + struct ext2_ext_attr_entry *entry; + struct ext2_inode_large *inode; + __u32 ea_inode_magic; + unsigned int minoff; + char *start; + size_t i; + errcode_t err; + + i = EXT2_INODE_SIZE(fs->super); + if (i < sizeof(*inode)) + i = sizeof(*inode); + err = ext2fs_get_memzero(i, &inode); + if (err) + return err; + + err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)inode, + EXT2_INODE_SIZE(fs->super)); + if (err) + goto out; + + /* Does the inode have size for EA? */ + if (EXT2_INODE_SIZE(fs->super) <= EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize + + sizeof(__u32)) { + err = EXT2_ET_INLINE_DATA_NO_SPACE; + goto out; + } + + minoff = EXT2_INODE_SIZE(fs->super) - sizeof(*inode) - sizeof(__u32); + memcpy(&ea_inode_magic, ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize, sizeof(__u32)); + if (ea_inode_magic == EXT2_EXT_ATTR_MAGIC) { + /* has xattrs. calculate the size */ + start= ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize + sizeof(__u32); + entry = (struct ext2_ext_attr_entry *) start; + while (!EXT2_EXT_IS_LAST_ENTRY(entry)) { + if (!entry->e_value_inum && entry->e_value_size) { + unsigned int offs = entry->e_value_offs; + if (offs < minoff) + minoff = offs; + } + entry = EXT2_EXT_ATTR_NEXT(entry); + } + *size = minoff - ((char *)entry - (char *)start) - sizeof(__u32); + } else { + /* no xattr. return a maximum size */ + *size = EXT2_EXT_ATTR_SIZE(minoff - + EXT2_EXT_ATTR_LEN(strlen("data")) - + EXT2_EXT_ATTR_ROUND - sizeof(__u32)); + } + +out: + ext2fs_free_mem(&inode); + return err; +} + +static errcode_t xattr_create_ea_inode(ext2_filsys fs, const void *value, + size_t value_len, ext2_ino_t *ea_ino) +{ + struct ext2_inode inode; + ext2_ino_t ino; + ext2_file_t file; + __u32 hash; + errcode_t ret; + + ret = ext2fs_new_inode(fs, 0, 0, 0, &ino); + if (ret) + return ret; + + memset(&inode, 0, sizeof(inode)); + inode.i_flags |= EXT4_EA_INODE_FL; + if (ext2fs_has_feature_extents(fs->super)) + inode.i_flags |= EXT4_EXTENTS_FL; + inode.i_size = 0; + inode.i_mode = LINUX_S_IFREG | 0600; + inode.i_links_count = 1; + ret = ext2fs_write_new_inode(fs, ino, &inode); + if (ret) + return ret; + /* + * ref_count and hash utilize inode's i_*time fields. + * ext2fs_write_new_inode() call above initializes these fields with + * current time. That's why ref count and hash updates are done + * separately below. + */ + ext2fs_set_ea_inode_ref(&inode, 1); + hash = ext2fs_crc32c_le(fs->csum_seed, value, value_len); + ext2fs_set_ea_inode_hash(&inode, hash); + + ret = ext2fs_write_inode(fs, ino, &inode); + if (ret) + return ret; + + ret = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &file); + if (ret) + return ret; + ret = ext2fs_file_write(file, value, value_len, NULL); + ext2fs_file_close(file); + if (ret) + return ret; + + ext2fs_inode_alloc_stats2(fs, ino, 1 /* inuse */, 0 /* isdir */); + + *ea_ino = ino; + return 0; +} + +static errcode_t xattr_inode_dec_ref(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_inode_large inode; + __u64 ref_count; + errcode_t ret; + + ret = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, + sizeof(inode)); + if (ret) + goto out; + + ref_count = ext2fs_get_ea_inode_ref(EXT2_INODE(&inode)); + ref_count--; + ext2fs_set_ea_inode_ref(EXT2_INODE(&inode), ref_count); + + if (ref_count) + goto write_out; + + inode.i_links_count = 0; + inode.i_dtime = fs->now ? fs->now : time(0); + + ret = ext2fs_free_ext_attr(fs, ino, &inode); + if (ret) + goto write_out; + + if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *)&inode)) { + ret = ext2fs_punch(fs, ino, (struct ext2_inode *)&inode, NULL, + 0, ~0ULL); + if (ret) + goto out; + } + + ext2fs_inode_alloc_stats2(fs, ino, -1 /* inuse */, 0 /* is_dir */); + +write_out: + ret = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, + sizeof(inode)); +out: + return ret; +} + +static errcode_t xattr_update_entry(ext2_filsys fs, struct ext2_xattr *x, + const char *name, const void *value, + size_t value_len, int in_inode) +{ + ext2_ino_t ea_ino = 0; + void *new_value = NULL; + char *new_name = NULL; + int name_len; + errcode_t ret; + + if (!x->name) { + name_len = strlen(name); + ret = ext2fs_get_mem(name_len + 1, &new_name); + if (ret) + goto fail; + memcpy(new_name, name, name_len + 1); + } + + ret = ext2fs_get_mem(value_len, &new_value); + if (ret) + goto fail; + memcpy(new_value, value, value_len); + + if (in_inode) { + ret = xattr_create_ea_inode(fs, value, value_len, &ea_ino); + if (ret) + goto fail; + } + + if (x->ea_ino) { + ret = xattr_inode_dec_ref(fs, x->ea_ino); + if (ret) + goto fail; + } + + if (!x->name) + x->name = new_name; + + if (x->value) + ext2fs_free_mem(&x->value); + x->value = new_value; + x->value_len = value_len; + x->ea_ino = ea_ino; + return 0; +fail: + if (new_name) + ext2fs_free_mem(&new_name); + if (new_value) + ext2fs_free_mem(&new_value); + if (ea_ino) + xattr_inode_dec_ref(fs, ea_ino); + return ret; +} + +static int xattr_find_position(struct ext2_xattr *attrs, int count, + const char *name) +{ + struct ext2_xattr *x; + int i; + const char *shortname, *x_shortname; + int name_idx, x_name_idx; + int shortname_len, x_shortname_len; + + find_ea_index(name, &shortname, &name_idx); + shortname_len = strlen(shortname); + + for (i = 0, x = attrs; i < count; i++, x++) { + find_ea_index(x->name, &x_shortname, &x_name_idx); + if (name_idx < x_name_idx) + break; + if (name_idx > x_name_idx) + continue; + + x_shortname_len = strlen(x_shortname); + if (shortname_len < x_shortname_len) + break; + if (shortname_len > x_shortname_len) + continue; + + if (memcmp(shortname, x_shortname, shortname_len) <= 0) + break; + } + return i; +} + +static errcode_t xattr_array_update(struct ext2_xattr_handle *h, + const char *name, + const void *value, size_t value_len, + int ibody_free, int block_free, + int old_idx, int in_inode) +{ + struct ext2_xattr tmp; + int add_to_ibody; + int needed; + int name_len, name_idx; + const char *shortname; + int new_idx; + int ret; + + find_ea_index(name, &shortname, &name_idx); + name_len = strlen(shortname); + + needed = EXT2_EXT_ATTR_LEN(name_len); + if (!in_inode) + needed += EXT2_EXT_ATTR_SIZE(value_len); + + if (old_idx >= 0 && old_idx < h->ibody_count) { + ibody_free += EXT2_EXT_ATTR_LEN(name_len); + if (!h->attrs[old_idx].ea_ino) + ibody_free += EXT2_EXT_ATTR_SIZE( + h->attrs[old_idx].value_len); + } + + if (needed <= ibody_free) { + if (old_idx < 0) { + new_idx = h->ibody_count; + add_to_ibody = 1; + goto add_new; + } + + /* Update the existing entry. */ + ret = xattr_update_entry(h->fs, &h->attrs[old_idx], name, + value, value_len, in_inode); + if (ret) + return ret; + if (h->ibody_count <= old_idx) { + /* Move entry from block to the end of ibody. */ + tmp = h->attrs[old_idx]; + memmove(h->attrs + h->ibody_count + 1, + h->attrs + h->ibody_count, + (old_idx - h->ibody_count) * sizeof(*h->attrs)); + h->attrs[h->ibody_count] = tmp; + h->ibody_count++; + } + return 0; + } + + if (h->ibody_count <= old_idx) { + block_free += EXT2_EXT_ATTR_LEN(name_len); + if (!h->attrs[old_idx].ea_ino) + block_free += + EXT2_EXT_ATTR_SIZE(h->attrs[old_idx].value_len); + } + + if (needed > block_free) + return EXT2_ET_EA_NO_SPACE; + + if (old_idx >= 0) { + /* Update the existing entry. */ + ret = xattr_update_entry(h->fs, &h->attrs[old_idx], name, + value, value_len, in_inode); + if (ret) + return ret; + if (old_idx < h->ibody_count) { + /* + * Move entry from ibody to the block. Note that + * entries in the block are sorted. + */ + new_idx = xattr_find_position(h->attrs + h->ibody_count, + h->count - h->ibody_count, name); + new_idx += h->ibody_count - 1; + tmp = h->attrs[old_idx]; + memmove(h->attrs + old_idx, h->attrs + old_idx + 1, + (new_idx - old_idx) * sizeof(*h->attrs)); + h->attrs[new_idx] = tmp; + h->ibody_count--; + } + return 0; + } + + new_idx = xattr_find_position(h->attrs + h->ibody_count, + h->count - h->ibody_count, name); + new_idx += h->ibody_count; + add_to_ibody = 0; + +add_new: + if (h->count == h->capacity) { + ret = ext2fs_xattrs_expand(h, 4); + if (ret) + return ret; + } + + ret = xattr_update_entry(h->fs, &h->attrs[h->count], name, value, + value_len, in_inode); + if (ret) + return ret; + + tmp = h->attrs[h->count]; + memmove(h->attrs + new_idx + 1, h->attrs + new_idx, + (h->count - new_idx)*sizeof(*h->attrs)); + h->attrs[new_idx] = tmp; + if (add_to_ibody) + h->ibody_count++; + h->count++; + return 0; +} + +static int space_used(struct ext2_xattr *attrs, int count) +{ + int total = 0; + struct ext2_xattr *x; + const char *shortname; + int i, len, name_idx; + + for (i = 0, x = attrs; i < count; i++, x++) { + find_ea_index(x->name, &shortname, &name_idx); + len = strlen(shortname); + total += EXT2_EXT_ATTR_LEN(len); + if (!x->ea_ino) + total += EXT2_EXT_ATTR_SIZE(x->value_len); + } + return total; +} + +/* + * The minimum size of EA value when you start storing it in an external inode + * size of block - size of header - size of 1 entry - 4 null bytes + */ +#define EXT4_XATTR_MIN_LARGE_EA_SIZE(b) \ + ((b) - EXT2_EXT_ATTR_LEN(3) - sizeof(struct ext2_ext_attr_header) - 4) + +errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *h, + const char *name, + const void *value, + size_t value_len) +{ + ext2_filsys fs = h->fs; + const int inode_size = EXT2_INODE_SIZE(fs->super); + struct ext2_inode_large *inode = NULL; + struct ext2_xattr *x; + char *new_value; + int ibody_free, block_free; + int in_inode = 0; + int old_idx = -1; + int extra_isize; + errcode_t ret; + + EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE); + + ret = ext2fs_get_mem(value_len, &new_value); + if (ret) + return ret; + if (!(h->flags & XATTR_HANDLE_FLAG_RAW) && + ((strcmp(name, "system.posix_acl_default") == 0) || + (strcmp(name, "system.posix_acl_access") == 0))) { + ret = convert_posix_acl_to_disk_buffer(value, value_len, + new_value, &value_len); + if (ret) + goto out; + } else + memcpy(new_value, value, value_len); + + /* Imitate kernel behavior by skipping update if value is the same. */ + for (x = h->attrs; x < h->attrs + h->count; x++) { + if (!strcmp(x->name, name)) { + if (!x->ea_ino && x->value_len == value_len && + !memcmp(x->value, new_value, value_len)) { + ret = 0; + goto out; + } + old_idx = x - h->attrs; + break; + } + } + + ret = ext2fs_get_memzero(inode_size, &inode); + if (ret) + goto out; + ret = ext2fs_read_inode_full(fs, h->ino, + (struct ext2_inode *)inode, + inode_size); + if (ret) + goto out; + if (inode_size > EXT2_GOOD_OLD_INODE_SIZE) { + extra_isize = inode->i_extra_isize; + if (extra_isize == 0) { + extra_isize = fs->super->s_want_extra_isize; + if (extra_isize == 0) + extra_isize = sizeof(__u32); + } + ibody_free = inode_size - EXT2_GOOD_OLD_INODE_SIZE; + ibody_free -= extra_isize; + /* Extended attribute magic and final null entry. */ + ibody_free -= sizeof(__u32) * 2; + ibody_free -= space_used(h->attrs, h->ibody_count); + } else + ibody_free = 0; + + /* Inline data can only go to ibody. */ + if (strcmp(name, "system.data") == 0) { + if (h->ibody_count <= old_idx) { + ret = EXT2_ET_FILESYSTEM_CORRUPTED; + goto out; + } + ret = xattr_array_update(h, name, new_value, value_len, + ibody_free, + 0 /* block_free */, old_idx, + 0 /* in_inode */); + if (ret) + goto out; + goto write_out; + } + + block_free = fs->blocksize; + block_free -= sizeof(struct ext2_ext_attr_header); + /* Final null entry. */ + block_free -= sizeof(__u32); + block_free -= space_used(h->attrs + h->ibody_count, + h->count - h->ibody_count); + + if (ext2fs_has_feature_ea_inode(fs->super) && + value_len > EXT4_XATTR_MIN_LARGE_EA_SIZE(fs->blocksize)) + in_inode = 1; + + ret = xattr_array_update(h, name, new_value, value_len, ibody_free, + block_free, old_idx, in_inode); + if (ret == EXT2_ET_EA_NO_SPACE && !in_inode && + ext2fs_has_feature_ea_inode(fs->super)) + ret = xattr_array_update(h, name, new_value, value_len, + ibody_free, block_free, old_idx, 1 /* in_inode */); + if (ret) + goto out; + +write_out: + ret = ext2fs_xattrs_write(h); +out: + if (inode) + ext2fs_free_mem(&inode); + ext2fs_free_mem(&new_value); + return ret; +} + +errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle, + const char *key) +{ + struct ext2_xattr *x; + struct ext2_xattr *end = handle->attrs + handle->count; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE); + for (x = handle->attrs; x < end; x++) { + if (strcmp(x->name, key) == 0) { + ext2fs_free_mem(&x->name); + ext2fs_free_mem(&x->value); + if (x->ea_ino) + xattr_inode_dec_ref(handle->fs, x->ea_ino); + memmove(x, x + 1, (end - x - 1)*sizeof(*x)); + memset(end - 1, 0, sizeof(*end)); + if (x < handle->attrs + handle->ibody_count) + handle->ibody_count--; + handle->count--; + return ext2fs_xattrs_write(handle); + } + } + + /* no key found, success! */ + return 0; +} + +errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino, + struct ext2_xattr_handle **handle) +{ + struct ext2_xattr_handle *h; + errcode_t err; + + if (!ext2fs_has_feature_xattr(fs->super) && + !ext2fs_has_feature_inline_data(fs->super)) + return EXT2_ET_MISSING_EA_FEATURE; + + err = ext2fs_get_memzero(sizeof(*h), &h); + if (err) + return err; + + h->magic = EXT2_ET_MAGIC_EA_HANDLE; + h->capacity = 4; + err = ext2fs_get_arrayzero(h->capacity, sizeof(struct ext2_xattr), + &h->attrs); + if (err) { + ext2fs_free_mem(&h); + return err; + } + h->count = 0; + h->ino = ino; + h->fs = fs; + *handle = h; + return 0; +} + +errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle) +{ + struct ext2_xattr_handle *h = *handle; + + EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE); + xattrs_free_keys(h); + ext2fs_free_mem(&h->attrs); + ext2fs_free_mem(handle); + return 0; +} + +errcode_t ext2fs_xattrs_count(struct ext2_xattr_handle *handle, size_t *count) +{ + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE); + *count = handle->count; + return 0; +} + +errcode_t ext2fs_xattrs_flags(struct ext2_xattr_handle *handle, + unsigned int *new_flags, unsigned int *old_flags) +{ + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE); + if (old_flags) + *old_flags = handle->flags; + if (new_flags) + handle->flags = *new_flags; + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/extent.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/extent.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,1747 @@ +/* + * extent.c --- routines to implement extents support + * + * Copyright (C) 2007 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" +#include "e2image.h" + +#undef DEBUG + +/* + * Definitions to be dropped in lib/ext2fs/ext2fs.h + */ + +/* + * Private definitions + */ + +struct extent_path { + char *buf; + int entries; + int max_entries; + int left; + int visit_num; + int flags; + blk64_t end_blk; + void *curr; +}; + + +struct ext2_extent_handle { + errcode_t magic; + ext2_filsys fs; + ext2_ino_t ino; + struct ext2_inode *inode; + struct ext2_inode inodebuf; + int type; + int level; + int max_depth; + int max_paths; + struct extent_path *path; +}; + +struct ext2_extent_path { + errcode_t magic; + int leaf_height; + blk64_t lblk; +}; + +/* + * Useful Debugging stuff + */ + +#ifdef DEBUG +static void dbg_show_header(struct ext3_extent_header *eh) +{ + printf("header: magic=%x entries=%u max=%u depth=%u generation=%u\n", + ext2fs_le16_to_cpu(eh->eh_magic), + ext2fs_le16_to_cpu(eh->eh_entries), + ext2fs_le16_to_cpu(eh->eh_max), + ext2fs_le16_to_cpu(eh->eh_depth), + ext2fs_le32_to_cpu(eh->eh_generation)); +} + +static void dbg_show_index(struct ext3_extent_idx *ix) +{ + printf("index: block=%u leaf=%u leaf_hi=%u unused=%u\n", + ext2fs_le32_to_cpu(ix->ei_block), + ext2fs_le32_to_cpu(ix->ei_leaf), + ext2fs_le16_to_cpu(ix->ei_leaf_hi), + ext2fs_le16_to_cpu(ix->ei_unused)); +} + +static void dbg_show_extent(struct ext3_extent *ex) +{ + printf("extent: block=%u-%u len=%u start=%u start_hi=%u\n", + ext2fs_le32_to_cpu(ex->ee_block), + ext2fs_le32_to_cpu(ex->ee_block) + + ext2fs_le16_to_cpu(ex->ee_len) - 1, + ext2fs_le16_to_cpu(ex->ee_len), + ext2fs_le32_to_cpu(ex->ee_start), + ext2fs_le16_to_cpu(ex->ee_start_hi)); +} + +static void dbg_print_extent(char *desc, struct ext2fs_extent *extent) +{ + if (desc) + printf("%s: ", desc); + printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ", + extent->e_lblk, extent->e_lblk + extent->e_len - 1, + extent->e_len, extent->e_pblk); + if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF) + fputs("LEAF ", stdout); + if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) + fputs("UNINIT ", stdout); + if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) + fputs("2ND_VISIT ", stdout); + if (!extent->e_flags) + fputs("(none)", stdout); + fputc('\n', stdout); + +} + +static void dump_path(const char *tag, struct ext2_extent_handle *handle, + struct extent_path *path) +{ + struct extent_path *ppp = path; + printf("%s: level=%d\n", tag, handle->level); + + do { + printf("%s: path=%ld buf=%p entries=%d max_entries=%d left=%d " + "visit_num=%d flags=0x%x end_blk=%llu curr=%p(%ld)\n", + tag, (ppp - handle->path), ppp->buf, ppp->entries, + ppp->max_entries, ppp->left, ppp->visit_num, ppp->flags, + ppp->end_blk, ppp->curr, ppp->curr - (void *)ppp->buf); + printf(" "); + dbg_show_header((struct ext3_extent_header *)ppp->buf); + if (ppp->curr) { + printf(" "); + dbg_show_index(ppp->curr); + printf(" "); + dbg_show_extent(ppp->curr); + } + ppp--; + } while (ppp >= handle->path); + fflush(stdout); + + return; +} + +#else +#define dbg_show_header(eh) do { } while (0) +#define dbg_show_index(ix) do { } while (0) +#define dbg_show_extent(ex) do { } while (0) +#define dbg_print_extent(desc, ex) do { } while (0) +#define dump_path(tag, handle, path) do { } while (0) +#endif + +/* + * Verify the extent header as being sane + */ +errcode_t ext2fs_extent_header_verify(void *ptr, int size) +{ + int eh_max, entry_size; + struct ext3_extent_header *eh = ptr; + + dbg_show_header(eh); + if (ext2fs_le16_to_cpu(eh->eh_magic) != EXT3_EXT_MAGIC) + return EXT2_ET_EXTENT_HEADER_BAD; + if (ext2fs_le16_to_cpu(eh->eh_entries) > ext2fs_le16_to_cpu(eh->eh_max)) + return EXT2_ET_EXTENT_HEADER_BAD; + if (eh->eh_depth == 0) + entry_size = sizeof(struct ext3_extent); + else + entry_size = sizeof(struct ext3_extent_idx); + + eh_max = (size - sizeof(*eh)) / entry_size; + /* Allow two extent-sized items at the end of the block, for + * ext4_extent_tail with checksum in the future. */ + if ((ext2fs_le16_to_cpu(eh->eh_max) > eh_max) || + (ext2fs_le16_to_cpu(eh->eh_max) < (eh_max - 2))) + return EXT2_ET_EXTENT_HEADER_BAD; + + return 0; +} + + +/* + * Begin functions to handle an inode's extent information + */ +void ext2fs_extent_free(ext2_extent_handle_t handle) +{ + int i; + + if (!handle) + return; + + if (handle->path) { + for (i = 1; i < handle->max_paths; i++) { + if (handle->path[i].buf) + ext2fs_free_mem(&handle->path[i].buf); + } + ext2fs_free_mem(&handle->path); + } + ext2fs_free_mem(&handle); +} + +errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino, + ext2_extent_handle_t *ret_handle) +{ + return ext2fs_extent_open2(fs, ino, NULL, ret_handle); +} + +errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + ext2_extent_handle_t *ret_handle) +{ + struct ext2_extent_handle *handle; + errcode_t retval; + int i; + struct ext3_extent_header *eh; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!inode) + if ((ino == 0) || (ino > fs->super->s_inodes_count)) + return EXT2_ET_BAD_INODE_NUM; + + retval = ext2fs_get_mem(sizeof(struct ext2_extent_handle), &handle); + if (retval) + return retval; + memset(handle, 0, sizeof(struct ext2_extent_handle)); + + handle->ino = ino; + handle->fs = fs; + + if (inode) { + handle->inode = inode; + } else { + handle->inode = &handle->inodebuf; + retval = ext2fs_read_inode(fs, ino, handle->inode); + if (retval) + goto errout; + } + + eh = (struct ext3_extent_header *) &handle->inode->i_block[0]; + + for (i=0; i < EXT2_N_BLOCKS; i++) + if (handle->inode->i_block[i]) + break; + if (i >= EXT2_N_BLOCKS) { + eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC); + eh->eh_depth = 0; + eh->eh_entries = 0; + i = (sizeof(handle->inode->i_block) - sizeof(*eh)) / + sizeof(struct ext3_extent); + eh->eh_max = ext2fs_cpu_to_le16(i); + handle->inode->i_flags |= EXT4_EXTENTS_FL; + } + + if (!(handle->inode->i_flags & EXT4_EXTENTS_FL)) { + retval = EXT2_ET_INODE_NOT_EXTENT; + goto errout; + } + + retval = ext2fs_extent_header_verify(eh, sizeof(handle->inode->i_block)); + if (retval) + goto errout; + + handle->max_depth = ext2fs_le16_to_cpu(eh->eh_depth); + handle->type = ext2fs_le16_to_cpu(eh->eh_magic); + + handle->max_paths = handle->max_depth + 1; + retval = ext2fs_get_memzero(handle->max_paths * + sizeof(struct extent_path), + &handle->path); + handle->path[0].buf = (char *) handle->inode->i_block; + + handle->path[0].left = handle->path[0].entries = + ext2fs_le16_to_cpu(eh->eh_entries); + handle->path[0].max_entries = ext2fs_le16_to_cpu(eh->eh_max); + handle->path[0].curr = 0; + handle->path[0].end_blk = + (EXT2_I_SIZE(handle->inode) + fs->blocksize - 1) >> + EXT2_BLOCK_SIZE_BITS(fs->super); + handle->path[0].visit_num = 1; + handle->level = 0; + handle->magic = EXT2_ET_MAGIC_EXTENT_HANDLE; + + *ret_handle = handle; + return 0; + +errout: + ext2fs_extent_free(handle); + return retval; +} + +/* + * This function is responsible for (optionally) moving through the + * extent tree and then returning the current extent + */ +errcode_t ext2fs_extent_get(ext2_extent_handle_t handle, + int flags, struct ext2fs_extent *extent) +{ + struct extent_path *path, *newpath; + struct ext3_extent_header *eh; + struct ext3_extent_idx *ix = 0; + struct ext3_extent *ex; + errcode_t retval; + blk64_t blk; + blk64_t end_blk; + int orig_op, op; + int failed_csum = 0; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + + if (!handle->path) + return EXT2_ET_NO_CURRENT_NODE; + + orig_op = op = flags & EXT2_EXTENT_MOVE_MASK; + +retry: + path = handle->path + handle->level; + if ((orig_op == EXT2_EXTENT_NEXT) || + (orig_op == EXT2_EXTENT_NEXT_LEAF)) { + if (handle->level < handle->max_depth) { + /* interior node */ + if (path->visit_num == 0) { + path->visit_num++; + op = EXT2_EXTENT_DOWN; + } else if (path->left > 0) + op = EXT2_EXTENT_NEXT_SIB; + else if (handle->level > 0) + op = EXT2_EXTENT_UP; + else + return EXT2_ET_EXTENT_NO_NEXT; + } else { + /* leaf node */ + if (path->left > 0) + op = EXT2_EXTENT_NEXT_SIB; + else if (handle->level > 0) + op = EXT2_EXTENT_UP; + else + return EXT2_ET_EXTENT_NO_NEXT; + } + if (op != EXT2_EXTENT_NEXT_SIB) { +#ifdef DEBUG_GET_EXTENT + printf("<<<< OP = %s\n", + (op == EXT2_EXTENT_DOWN) ? "down" : + ((op == EXT2_EXTENT_UP) ? "up" : "unknown")); +#endif + } + } + + if ((orig_op == EXT2_EXTENT_PREV) || + (orig_op == EXT2_EXTENT_PREV_LEAF)) { + if (handle->level < handle->max_depth) { + /* interior node */ + if (path->visit_num > 0 ) { + /* path->visit_num = 0; */ + op = EXT2_EXTENT_DOWN_AND_LAST; + } else if (path->left < path->entries-1) + op = EXT2_EXTENT_PREV_SIB; + else if (handle->level > 0) + op = EXT2_EXTENT_UP; + else + return EXT2_ET_EXTENT_NO_PREV; + } else { + /* leaf node */ + if (path->left < path->entries-1) + op = EXT2_EXTENT_PREV_SIB; + else if (handle->level > 0) + op = EXT2_EXTENT_UP; + else + return EXT2_ET_EXTENT_NO_PREV; + } + if (op != EXT2_EXTENT_PREV_SIB) { +#ifdef DEBUG_GET_EXTENT + printf("<<<< OP = %s\n", + (op == EXT2_EXTENT_DOWN_AND_LAST) ? "down/last" : + ((op == EXT2_EXTENT_UP) ? "up" : "unknown")); +#endif + } + } + + if (orig_op == EXT2_EXTENT_LAST_LEAF) { + if ((handle->level < handle->max_depth) && + (path->left == 0)) + op = EXT2_EXTENT_DOWN; + else + op = EXT2_EXTENT_LAST_SIB; +#ifdef DEBUG_GET_EXTENT + printf("<<<< OP = %s\n", + (op == EXT2_EXTENT_DOWN) ? "down" : "last_sib"); +#endif + } + + switch (op) { + case EXT2_EXTENT_CURRENT: + ix = path->curr; + break; + case EXT2_EXTENT_ROOT: + handle->level = 0; + path = handle->path + handle->level; + /* fallthrough */ + case EXT2_EXTENT_FIRST_SIB: + path->left = path->entries; + path->curr = 0; + /* fallthrough */ + case EXT2_EXTENT_NEXT_SIB: + if (path->left <= 0) + return EXT2_ET_EXTENT_NO_NEXT; + if (path->curr) { + ix = path->curr; + ix++; + } else { + eh = (struct ext3_extent_header *) path->buf; + ix = EXT_FIRST_INDEX(eh); + } + path->left--; + path->curr = ix; + path->visit_num = 0; + break; + case EXT2_EXTENT_PREV_SIB: + if (!path->curr || + path->left+1 >= path->entries) + return EXT2_ET_EXTENT_NO_PREV; + ix = path->curr; + ix--; + path->curr = ix; + path->left++; + if (handle->level < handle->max_depth) + path->visit_num = 1; + break; + case EXT2_EXTENT_LAST_SIB: + eh = (struct ext3_extent_header *) path->buf; + path->curr = EXT_LAST_EXTENT(eh); + ix = path->curr; + path->left = 0; + path->visit_num = 0; + break; + case EXT2_EXTENT_UP: + if (handle->level <= 0) + return EXT2_ET_EXTENT_NO_UP; + handle->level--; + path--; + ix = path->curr; + if ((orig_op == EXT2_EXTENT_PREV) || + (orig_op == EXT2_EXTENT_PREV_LEAF)) + path->visit_num = 0; + break; + case EXT2_EXTENT_DOWN: + case EXT2_EXTENT_DOWN_AND_LAST: + if (!path->curr ||(handle->level >= handle->max_depth)) + return EXT2_ET_EXTENT_NO_DOWN; + + ix = path->curr; + newpath = path + 1; + if (!newpath->buf) { + retval = ext2fs_get_mem(handle->fs->blocksize, + &newpath->buf); + if (retval) + return retval; + } + blk = ext2fs_le32_to_cpu(ix->ei_leaf) + + ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); + if ((handle->fs->flags & EXT2_FLAG_IMAGE_FILE) && + (handle->fs->io != handle->fs->image_io)) + memset(newpath->buf, 0, handle->fs->blocksize); + else { + retval = io_channel_read_blk64(handle->fs->io, + blk, 1, newpath->buf); + if (retval) + return retval; + } + handle->level++; + + eh = (struct ext3_extent_header *) newpath->buf; + + retval = ext2fs_extent_header_verify(eh, handle->fs->blocksize); + if (retval) { + handle->level--; + return retval; + } + + if (!(handle->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_extent_block_csum_verify(handle->fs, handle->ino, + eh)) + failed_csum = 1; + + newpath->left = newpath->entries = + ext2fs_le16_to_cpu(eh->eh_entries); + newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max); + + if (path->left > 0) { + ix++; + newpath->end_blk = ext2fs_le32_to_cpu(ix->ei_block); + } else + newpath->end_blk = path->end_blk; + + path = newpath; + if (op == EXT2_EXTENT_DOWN) { + ix = EXT_FIRST_INDEX((struct ext3_extent_header *) eh); + path->curr = ix; + path->left = path->entries - 1; + path->visit_num = 0; + } else { + ix = EXT_LAST_INDEX((struct ext3_extent_header *) eh); + path->curr = ix; + path->left = 0; + if (handle->level < handle->max_depth) + path->visit_num = 1; + } +#ifdef DEBUG_GET_EXTENT + printf("Down to level %d/%d, end_blk=%llu\n", + handle->level, handle->max_depth, + path->end_blk); +#endif + break; + default: + return EXT2_ET_OP_NOT_SUPPORTED; + } + + if (!ix) + return EXT2_ET_NO_CURRENT_NODE; + + extent->e_flags = 0; +#ifdef DEBUG_GET_EXTENT + printf("(Left %d)\n", path->left); +#endif + + if (handle->level == handle->max_depth) { + ex = (struct ext3_extent *) ix; + + extent->e_pblk = ext2fs_le32_to_cpu(ex->ee_start) + + ((__u64) ext2fs_le16_to_cpu(ex->ee_start_hi) << 32); + extent->e_lblk = ext2fs_le32_to_cpu(ex->ee_block); + extent->e_len = ext2fs_le16_to_cpu(ex->ee_len); + extent->e_flags |= EXT2_EXTENT_FLAGS_LEAF; + if (extent->e_len > EXT_INIT_MAX_LEN) { + extent->e_len -= EXT_INIT_MAX_LEN; + extent->e_flags |= EXT2_EXTENT_FLAGS_UNINIT; + } + } else { + extent->e_pblk = ext2fs_le32_to_cpu(ix->ei_leaf) + + ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); + extent->e_lblk = ext2fs_le32_to_cpu(ix->ei_block); + if (path->left > 0) { + ix++; + end_blk = ext2fs_le32_to_cpu(ix->ei_block); + } else + end_blk = path->end_blk; + + extent->e_len = end_blk - extent->e_lblk; + } + if (path->visit_num) + extent->e_flags |= EXT2_EXTENT_FLAGS_SECOND_VISIT; + + if (((orig_op == EXT2_EXTENT_NEXT_LEAF) || + (orig_op == EXT2_EXTENT_PREV_LEAF)) && + (handle->level != handle->max_depth)) + goto retry; + + if ((orig_op == EXT2_EXTENT_LAST_LEAF) && + ((handle->level != handle->max_depth) || + (path->left != 0))) + goto retry; + + if (failed_csum) + return EXT2_ET_EXTENT_CSUM_INVALID; + + return 0; +} + +static errcode_t update_path(ext2_extent_handle_t handle) +{ + blk64_t blk; + errcode_t retval; + struct ext3_extent_idx *ix; + struct ext3_extent_header *eh; + + if (handle->level == 0) { + retval = ext2fs_write_inode(handle->fs, handle->ino, + handle->inode); + } else { + ix = handle->path[handle->level - 1].curr; + blk = ext2fs_le32_to_cpu(ix->ei_leaf) + + ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); + + /* then update the checksum */ + eh = (struct ext3_extent_header *) + handle->path[handle->level].buf; + retval = ext2fs_extent_block_csum_set(handle->fs, handle->ino, + eh); + if (retval) + return retval; + + retval = io_channel_write_blk64(handle->fs->io, + blk, 1, handle->path[handle->level].buf); + } + return retval; +} + +#if 0 +errcode_t ext2fs_extent_save_path(ext2_extent_handle_t handle, + ext2_extent_path_t *ret_path) +{ + ext2_extent_path_t save_path; + struct ext2fs_extent extent; + struct ext2_extent_info info; + errcode_t retval; + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); + if (retval) + return retval; + + retval = ext2fs_extent_get_info(handle, &info); + if (retval) + return retval; + + retval = ext2fs_get_mem(sizeof(struct ext2_extent_path), &save_path); + if (retval) + return retval; + memset(save_path, 0, sizeof(struct ext2_extent_path)); + + save_path->magic = EXT2_ET_MAGIC_EXTENT_PATH; + save_path->leaf_height = info.max_depth - info.curr_level - 1; + save_path->lblk = extent.e_lblk; + + *ret_path = save_path; + return 0; +} + +errcode_t ext2fs_extent_free_path(ext2_extent_path_t path) +{ + EXT2_CHECK_MAGIC(path, EXT2_ET_MAGIC_EXTENT_PATH); + + ext2fs_free_mem(&path); + return 0; +} +#endif + +/* + * Go to the node at leaf_level which contains logical block blk. + * + * leaf_level is height from the leaf node level, i.e. + * leaf_level 0 is at leaf node, leaf_level 1 is 1 above etc. + * + * If "blk" has no mapping (hole) then handle is left at last + * extent before blk. + */ +errcode_t ext2fs_extent_goto2(ext2_extent_handle_t handle, + int leaf_level, blk64_t blk) +{ + struct ext2fs_extent extent; + errcode_t retval; + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent); + if (retval) { + if (retval == EXT2_ET_EXTENT_NO_NEXT) + retval = EXT2_ET_EXTENT_NOT_FOUND; + return retval; + } + + if (leaf_level > handle->max_depth) { +#ifdef DEBUG + printf("leaf level %d greater than tree depth %d\n", + leaf_level, handle->max_depth); +#endif + return EXT2_ET_OP_NOT_SUPPORTED; + } + +#ifdef DEBUG + printf("goto extent ino %u, level %d, %llu\n", handle->ino, + leaf_level, blk); +#endif + +#ifdef DEBUG_GOTO_EXTENTS + dbg_print_extent("root", &extent); +#endif + while (1) { + if (handle->max_depth - handle->level == leaf_level) { + /* block is in this &extent */ + if ((blk >= extent.e_lblk) && + (blk < extent.e_lblk + extent.e_len)) + return 0; + if (blk < extent.e_lblk) { + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_PREV_SIB, + &extent); + return EXT2_ET_EXTENT_NOT_FOUND; + } + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_NEXT_SIB, + &extent); + if (retval == EXT2_ET_EXTENT_NO_NEXT) + return EXT2_ET_EXTENT_NOT_FOUND; + if (retval) + return retval; + continue; + } + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_SIB, + &extent); + if (retval == EXT2_ET_EXTENT_NO_NEXT) + goto go_down; + if (retval) + return retval; + +#ifdef DEBUG_GOTO_EXTENTS + dbg_print_extent("next", &extent); +#endif + if (blk == extent.e_lblk) + goto go_down; + if (blk > extent.e_lblk) + continue; + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_PREV_SIB, + &extent); + if (retval) + return retval; + +#ifdef DEBUG_GOTO_EXTENTS + dbg_print_extent("prev", &extent); +#endif + + go_down: + retval = ext2fs_extent_get(handle, EXT2_EXTENT_DOWN, + &extent); + if (retval) + return retval; + +#ifdef DEBUG_GOTO_EXTENTS + dbg_print_extent("down", &extent); +#endif + } +} + +errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle, + blk64_t blk) +{ + return ext2fs_extent_goto2(handle, 0, blk); +} + +/* + * Traverse back up to root fixing parents of current node as needed. + * + * If we changed start of first entry in a node, fix parent index start + * and so on. + * + * Safe to call for any position in node; if not at the first entry, + * it will simply return. + * + * Note a subtlety of this function -- if there happen to be two extents + * mapping the same lblk and someone calls fix_parents on the second of the two + * extents, the position of the extent handle after the call will be the second + * extent if nothing happened, or the first extent if something did. A caller + * in this situation must use ext2fs_extent_goto() after calling this function. + * Or simply don't map the same lblk with two extents, ever. + */ +errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle) +{ + int retval = 0; + int orig_height; + blk64_t start; + struct extent_path *path; + struct ext2fs_extent extent; + struct ext2_extent_info info; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + + if (!(handle->fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + if (!handle->path) + return EXT2_ET_NO_CURRENT_NODE; + + path = handle->path + handle->level; + if (!path->curr) + return EXT2_ET_NO_CURRENT_NODE; + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); + if (retval) + goto done; + + /* modified node's start block */ + start = extent.e_lblk; + + if ((retval = ext2fs_extent_get_info(handle, &info))) + return retval; + orig_height = info.max_depth - info.curr_level; + + /* traverse up until index not first, or startblk matches, or top */ + while (handle->level > 0 && + (path->left == path->entries - 1)) { + retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent); + if (retval) + goto done; + if (extent.e_lblk == start) + break; + path = handle->path + handle->level; + extent.e_len += (extent.e_lblk - start); + extent.e_lblk = start; + retval = ext2fs_extent_replace(handle, 0, &extent); + if (retval) + goto done; + update_path(handle); + } + + /* put handle back to where we started */ + retval = ext2fs_extent_goto2(handle, orig_height, start); +done: + return retval; +} + +errcode_t ext2fs_extent_replace(ext2_extent_handle_t handle, + int flags EXT2FS_ATTR((unused)), + struct ext2fs_extent *extent) +{ + struct extent_path *path; + struct ext3_extent_idx *ix; + struct ext3_extent *ex; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + + if (!(handle->fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + if (!handle->path) + return EXT2_ET_NO_CURRENT_NODE; + + path = handle->path + handle->level; + if (!path->curr) + return EXT2_ET_NO_CURRENT_NODE; + +#ifdef DEBUG + printf("extent replace: %u ", handle->ino); + dbg_print_extent(0, extent); +#endif + + if (handle->level == handle->max_depth) { + ex = path->curr; + + ex->ee_block = ext2fs_cpu_to_le32(extent->e_lblk); + ex->ee_start = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF); + ex->ee_start_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32); + if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) { + if (extent->e_len > EXT_UNINIT_MAX_LEN) + return EXT2_ET_EXTENT_INVALID_LENGTH; + ex->ee_len = ext2fs_cpu_to_le16(extent->e_len + + EXT_INIT_MAX_LEN); + } else { + if (extent->e_len > EXT_INIT_MAX_LEN) + return EXT2_ET_EXTENT_INVALID_LENGTH; + ex->ee_len = ext2fs_cpu_to_le16(extent->e_len); + } + } else { + ix = path->curr; + + ix->ei_leaf = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF); + ix->ei_leaf_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32); + ix->ei_block = ext2fs_cpu_to_le32(extent->e_lblk); + ix->ei_unused = 0; + } + update_path(handle); + return 0; +} + +static int splitting_at_eof(struct ext2_extent_handle *handle, + struct extent_path *path) +{ + struct extent_path *ppp = path; + dump_path(__func__, handle, path); + + if (handle->level == 0) + return 0; + + do { + if (ppp->left) + return 0; + ppp--; + } while (ppp >= handle->path); + + return 1; +} + +/* + * allocate a new block, move half the current node to it, and update parent + * + * handle will be left pointing at original record. + */ +static errcode_t extent_node_split(ext2_extent_handle_t handle, + int expand_allowed) +{ + errcode_t retval = 0; + blk64_t new_node_pblk; + blk64_t new_node_start; + blk64_t orig_lblk; + blk64_t goal_blk = 0; + int orig_height; + char *block_buf = NULL; + struct ext2fs_extent extent; + struct extent_path *path, *newpath = 0; + struct ext3_extent_header *eh, *neweh; + int tocopy; + int new_root = 0; + struct ext2_extent_info info; + int no_balance; + + /* basic sanity */ + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + + if (!(handle->fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + if (!handle->path) + return EXT2_ET_NO_CURRENT_NODE; + +#ifdef DEBUG + printf("splitting node at level %d\n", handle->level); +#endif + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); + if (retval) + goto done; + + retval = ext2fs_extent_get_info(handle, &info); + if (retval) + goto done; + + /* save the position we were originally splitting... */ + orig_height = info.max_depth - info.curr_level; + orig_lblk = extent.e_lblk; + + /* Try to put the index block before the first extent */ + path = handle->path + handle->level; + eh = (struct ext3_extent_header *) path->buf; + if (handle->level == handle->max_depth) { + struct ext3_extent *ex; + + ex = EXT_FIRST_EXTENT(eh); + goal_blk = ext2fs_le32_to_cpu(ex->ee_start) + + ((__u64) ext2fs_le16_to_cpu(ex->ee_start_hi) << 32); + } else { + struct ext3_extent_idx *ix; + + ix = EXT_FIRST_INDEX(eh); + goal_blk = ext2fs_le32_to_cpu(ix->ei_leaf) + + ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); + } + goal_blk -= EXT2FS_CLUSTER_RATIO(handle->fs); + goal_blk &= ~EXT2FS_CLUSTER_MASK(handle->fs); + + /* Is there room in the parent for a new entry? */ + if (handle->level && + (handle->path[handle->level - 1].entries >= + handle->path[handle->level - 1].max_entries)) { + +#ifdef DEBUG + printf("parent level %d full; splitting it too\n", + handle->level - 1); +#endif + /* split the parent */ + retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent); + if (retval) + goto done; + + retval = extent_node_split(handle, expand_allowed); + if (retval) + goto done; + + /* get handle back to our original split position */ + retval = ext2fs_extent_goto2(handle, orig_height, orig_lblk); + if (retval) + goto done; + } + + /* At this point, parent should have room for this split */ + path = handle->path + handle->level; + if (!path->curr) + return EXT2_ET_NO_CURRENT_NODE; + + /* + * Normally, we try to split a full node in half. This doesn't turn + * out so well if we're tacking extents on the end of the file because + * then we're stuck with a tree of half-full extent blocks. This of + * course doesn't apply to the root level. + */ + no_balance = expand_allowed ? splitting_at_eof(handle, path) : 0; + + /* extent header of the current node we'll split */ + eh = (struct ext3_extent_header *)path->buf; + + /* splitting root level means moving them all out */ + if (handle->level == 0) { + new_root = 1; + tocopy = ext2fs_le16_to_cpu(eh->eh_entries); + retval = ext2fs_get_memzero((handle->max_paths + 1) * + sizeof(struct extent_path), + &newpath); + if (retval) + goto done; + } else { + if (no_balance) + tocopy = 1; + else + tocopy = ext2fs_le16_to_cpu(eh->eh_entries) / 2; + } + +#ifdef DEBUG + printf("will copy out %d of %d entries at level %d\n", + tocopy, ext2fs_le16_to_cpu(eh->eh_entries), + handle->level); +#endif + + if (!tocopy && !no_balance) { +#ifdef DEBUG + printf("Nothing to copy to new block!\n"); +#endif + retval = EXT2_ET_CANT_SPLIT_EXTENT; + goto done; + } + + /* first we need a new block, or can do nothing. */ + block_buf = malloc(handle->fs->blocksize); + if (!block_buf) { + retval = ENOMEM; + goto done; + } + + if (!goal_blk) + goal_blk = ext2fs_find_inode_goal(handle->fs, handle->ino, + handle->inode, 0); + retval = ext2fs_alloc_block2(handle->fs, goal_blk, block_buf, + &new_node_pblk); + if (retval) + goto done; + +#ifdef DEBUG + printf("will copy to new node at block %lu\n", + (unsigned long) new_node_pblk); +#endif + + /* Copy data into new block buffer */ + /* First the header for the new block... */ + neweh = (struct ext3_extent_header *) block_buf; + memcpy(neweh, eh, sizeof(struct ext3_extent_header)); + neweh->eh_entries = ext2fs_cpu_to_le16(tocopy); + neweh->eh_max = ext2fs_cpu_to_le16((handle->fs->blocksize - + sizeof(struct ext3_extent_header)) / + sizeof(struct ext3_extent)); + + /* then the entries for the new block... */ + memcpy(EXT_FIRST_INDEX(neweh), + EXT_FIRST_INDEX(eh) + + (ext2fs_le16_to_cpu(eh->eh_entries) - tocopy), + sizeof(struct ext3_extent_idx) * tocopy); + + new_node_start = ext2fs_le32_to_cpu(EXT_FIRST_INDEX(neweh)->ei_block); + + /* then update the checksum */ + retval = ext2fs_extent_block_csum_set(handle->fs, handle->ino, neweh); + if (retval) + goto done; + + /* ...and write the new node block out to disk. */ + retval = io_channel_write_blk64(handle->fs->io, new_node_pblk, 1, + block_buf); + + if (retval) + goto done; + + /* OK! we've created the new node; now adjust the tree */ + + /* current path now has fewer active entries, we copied some out */ + if (handle->level == 0) { + memcpy(newpath, path, + sizeof(struct extent_path) * handle->max_paths); + handle->path = newpath; + newpath = path; + path = handle->path; + path->entries = 1; + path->left = path->max_entries - 1; + handle->max_depth++; + handle->max_paths++; + eh->eh_depth = ext2fs_cpu_to_le16(handle->max_depth); + } else { + path->entries -= tocopy; + path->left -= tocopy; + } + + eh->eh_entries = ext2fs_cpu_to_le16(path->entries); + /* this writes out the node, incl. the modified header */ + retval = update_path(handle); + if (retval) + goto done; + + /* now go up and insert/replace index for new node we created */ + if (new_root) { + retval = ext2fs_extent_get(handle, EXT2_EXTENT_FIRST_SIB, &extent); + if (retval) + goto done; + + extent.e_lblk = new_node_start; + extent.e_pblk = new_node_pblk; + extent.e_len = handle->path[0].end_blk - extent.e_lblk; + retval = ext2fs_extent_replace(handle, 0, &extent); + if (retval) + goto done; + } else { + __u32 new_node_length; + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent); + /* will insert after this one; it's length is shorter now */ + new_node_length = new_node_start - extent.e_lblk; + extent.e_len -= new_node_length; + retval = ext2fs_extent_replace(handle, 0, &extent); + if (retval) + goto done; + + /* now set up the new extent and insert it */ + extent.e_lblk = new_node_start; + extent.e_pblk = new_node_pblk; + extent.e_len = new_node_length; + retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER, &extent); + if (retval) + goto done; + } + + /* get handle back to our original position */ + retval = ext2fs_extent_goto2(handle, orig_height, orig_lblk); + if (retval) + goto done; + + /* new node hooked in, so update inode block count (do this here?) */ + ext2fs_iblk_add_blocks(handle->fs, handle->inode, 1); + retval = ext2fs_write_inode(handle->fs, handle->ino, + handle->inode); + if (retval) + goto done; + +done: + if (newpath) + ext2fs_free_mem(&newpath); + free(block_buf); + + return retval; +} + +errcode_t ext2fs_extent_node_split(ext2_extent_handle_t handle) +{ + return extent_node_split(handle, 0); +} + +errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags, + struct ext2fs_extent *extent) +{ + struct extent_path *path; + struct ext3_extent_idx *ix; + struct ext3_extent_header *eh; + errcode_t retval; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + + if (!(handle->fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + if (!handle->path) + return EXT2_ET_NO_CURRENT_NODE; + +#ifdef DEBUG + printf("extent insert: %u ", handle->ino); + dbg_print_extent(0, extent); +#endif + + path = handle->path + handle->level; + + if (path->entries >= path->max_entries) { + if (flags & EXT2_EXTENT_INSERT_NOSPLIT) { + return EXT2_ET_CANT_INSERT_EXTENT; + } else { +#ifdef DEBUG + printf("node full (level %d) - splitting\n", + handle->level); +#endif + retval = extent_node_split(handle, 1); + if (retval) + return retval; + path = handle->path + handle->level; + } + } + + eh = (struct ext3_extent_header *) path->buf; + if (path->curr) { + ix = path->curr; + if (flags & EXT2_EXTENT_INSERT_AFTER) { + ix++; + path->left--; + } + } else { + ix = EXT_FIRST_INDEX(eh); + path->left = -1; + } + + path->curr = ix; + + if (path->left >= 0) + memmove(ix + 1, ix, + (path->left+1) * sizeof(struct ext3_extent_idx)); + path->left++; + path->entries++; + + eh = (struct ext3_extent_header *) path->buf; + eh->eh_entries = ext2fs_cpu_to_le16(path->entries); + + retval = ext2fs_extent_replace(handle, 0, extent); + if (retval) + goto errout; + + retval = update_path(handle); + if (retval) + goto errout; + + return 0; + +errout: + ext2fs_extent_delete(handle, 0); + return retval; +} + +/* + * Sets the physical block for a logical file block in the extent tree. + * + * May: map unmapped, unmap mapped, or remap mapped blocks. + * + * Mapping an unmapped block adds a single-block extent. + * + * Unmapping first or last block modifies extent in-place + * - But may need to fix parent's starts too in first-block case + * + * Mapping any unmapped block requires adding a (single-block) extent + * and inserting into proper point in tree. + * + * Modifying (unmapping or remapping) a block in the middle + * of an extent requires splitting the extent. + * - Remapping case requires new single-block extent. + * + * Remapping first or last block adds an extent. + * + * We really need extent adding to be smart about merging. + */ + +errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle, + blk64_t logical, blk64_t physical, int flags) +{ + errcode_t ec, retval = 0; + int mapped = 1; /* logical is mapped? */ + int orig_height; + int extent_uninit = 0; + int prev_uninit = 0; + int next_uninit = 0; + int new_uninit = 0; + int max_len = EXT_INIT_MAX_LEN; + int has_prev, has_next; + blk64_t orig_lblk; + struct extent_path *path; + struct ext2fs_extent extent, next_extent, prev_extent; + struct ext2fs_extent newextent; + struct ext2_extent_info info; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + +#ifdef DEBUG + printf("set_bmap ino %u log %lld phys %lld flags %d\n", + handle->ino, logical, physical, flags); +#endif + + if (!(handle->fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + if (!handle->path) + return EXT2_ET_NO_CURRENT_NODE; + + path = handle->path + handle->level; + + if (flags & EXT2_EXTENT_SET_BMAP_UNINIT) { + new_uninit = 1; + max_len = EXT_UNINIT_MAX_LEN; + } + + /* if (re)mapping, set up new extent to insert */ + if (physical) { + newextent.e_len = 1; + newextent.e_pblk = physical; + newextent.e_lblk = logical; + newextent.e_flags = EXT2_EXTENT_FLAGS_LEAF; + if (new_uninit) + newextent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT; + } + + /* special case if the extent tree is completely empty */ + if ((handle->max_depth == 0) && (path->entries == 0)) { + retval = ext2fs_extent_insert(handle, 0, &newextent); + return retval; + } + + /* save our original location in the extent tree */ + if ((retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, + &extent))) { + if (retval != EXT2_ET_NO_CURRENT_NODE) + return retval; + memset(&extent, 0, sizeof(extent)); + } + if ((retval = ext2fs_extent_get_info(handle, &info))) + return retval; + orig_height = info.max_depth - info.curr_level; + orig_lblk = extent.e_lblk; + + /* go to the logical spot we want to (re/un)map */ + retval = ext2fs_extent_goto(handle, logical); + if (retval) { + if (retval == EXT2_ET_EXTENT_NOT_FOUND) { + retval = 0; + mapped = 0; + if (!physical) { +#ifdef DEBUG + printf("block %llu already unmapped\n", + logical); +#endif + goto done; + } + } else + goto done; + } + + /* + * This may be the extent *before* the requested logical, + * if it's currently unmapped. + * + * Get the previous and next leaf extents, if they are present. + */ + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); + if (retval) + goto done; + if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) + extent_uninit = 1; + retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, &next_extent); + if (retval) { + has_next = 0; + if (retval != EXT2_ET_EXTENT_NO_NEXT) + goto done; + } else { + dbg_print_extent("set_bmap: next_extent", + &next_extent); + has_next = 1; + if (next_extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) + next_uninit = 1; + } + retval = ext2fs_extent_goto(handle, logical); + if (retval && retval != EXT2_ET_EXTENT_NOT_FOUND) + goto done; + retval = ext2fs_extent_get(handle, EXT2_EXTENT_PREV_LEAF, &prev_extent); + if (retval) { + has_prev = 0; + if (retval != EXT2_ET_EXTENT_NO_PREV) + goto done; + } else { + has_prev = 1; + dbg_print_extent("set_bmap: prev_extent", + &prev_extent); + if (prev_extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) + prev_uninit = 1; + } + retval = ext2fs_extent_goto(handle, logical); + if (retval && retval != EXT2_ET_EXTENT_NOT_FOUND) + goto done; + + /* check if already pointing to the requested physical */ + if (mapped && (new_uninit == extent_uninit) && + (extent.e_pblk + (logical - extent.e_lblk) == physical)) { +#ifdef DEBUG + printf("physical block (at %llu) unchanged\n", logical); +#endif + goto done; + } + + if (!mapped) { +#ifdef DEBUG + printf("mapping unmapped logical block %llu\n", logical); +#endif + if ((logical == extent.e_lblk + extent.e_len) && + (physical == extent.e_pblk + extent.e_len) && + (new_uninit == extent_uninit) && + ((int) extent.e_len < max_len-1)) { + extent.e_len++; + retval = ext2fs_extent_replace(handle, 0, &extent); + } else if ((logical == extent.e_lblk - 1) && + (physical == extent.e_pblk - 1) && + (new_uninit == extent_uninit) && + ((int) extent.e_len < max_len - 1)) { + extent.e_len++; + extent.e_lblk--; + extent.e_pblk--; + retval = ext2fs_extent_replace(handle, 0, &extent); + } else if (has_next && + (logical == next_extent.e_lblk - 1) && + (physical == next_extent.e_pblk - 1) && + (new_uninit == next_uninit) && + ((int) next_extent.e_len < max_len - 1)) { + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_NEXT_LEAF, + &next_extent); + if (retval) + goto done; + next_extent.e_len++; + next_extent.e_lblk--; + next_extent.e_pblk--; + retval = ext2fs_extent_replace(handle, 0, &next_extent); + } else if (logical < extent.e_lblk) + retval = ext2fs_extent_insert(handle, 0, &newextent); + else + retval = ext2fs_extent_insert(handle, + EXT2_EXTENT_INSERT_AFTER, &newextent); + if (retval) + goto done; + retval = ext2fs_extent_fix_parents(handle); + if (retval) + goto done; + } else if ((logical == extent.e_lblk) && (extent.e_len == 1)) { +#ifdef DEBUG + printf("(re/un)mapping only block in extent\n"); +#endif + if (physical) { + retval = ext2fs_extent_replace(handle, 0, &newextent); + } else { + retval = ext2fs_extent_delete(handle, 0); + if (retval) + goto done; + ec = ext2fs_extent_fix_parents(handle); + if (ec != EXT2_ET_NO_CURRENT_NODE) + retval = ec; + } + + if (retval) + goto done; + } else if (logical == extent.e_lblk + extent.e_len - 1) { +#ifdef DEBUG + printf("(re/un)mapping last block in extent\n"); +#endif + if (physical) { + if (has_next && + (logical == (next_extent.e_lblk - 1)) && + (physical == (next_extent.e_pblk - 1)) && + (new_uninit == next_uninit) && + ((int) next_extent.e_len < max_len - 1)) { + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_NEXT_LEAF, &next_extent); + if (retval) + goto done; + next_extent.e_len++; + next_extent.e_lblk--; + next_extent.e_pblk--; + retval = ext2fs_extent_replace(handle, 0, + &next_extent); + if (retval) + goto done; + } else + retval = ext2fs_extent_insert(handle, + EXT2_EXTENT_INSERT_AFTER, &newextent); + if (retval) + goto done; + retval = ext2fs_extent_fix_parents(handle); + if (retval) + goto done; + /* + * Now pointing at inserted extent; move back to prev. + * + * We cannot use EXT2_EXTENT_PREV to go back; note the + * subtlety in the comment for fix_parents(). + */ + retval = ext2fs_extent_goto(handle, logical); + if (retval) + goto done; + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_CURRENT, + &extent); + if (retval) + goto done; + } + extent.e_len--; + retval = ext2fs_extent_replace(handle, 0, &extent); + if (retval) + goto done; + } else if (logical == extent.e_lblk) { +#ifdef DEBUG + printf("(re/un)mapping first block in extent\n"); +#endif + if (physical) { + if (has_prev && + (logical == (prev_extent.e_lblk + + prev_extent.e_len)) && + (physical == (prev_extent.e_pblk + + prev_extent.e_len)) && + (new_uninit == prev_uninit) && + ((int) prev_extent.e_len < max_len-1)) { + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_PREV_LEAF, &prev_extent); + if (retval) + goto done; + prev_extent.e_len++; + retval = ext2fs_extent_replace(handle, 0, + &prev_extent); + } else + retval = ext2fs_extent_insert(handle, + 0, &newextent); + if (retval) + goto done; + retval = ext2fs_extent_fix_parents(handle); + if (retval) + goto done; + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_NEXT_LEAF, + &extent); + if (retval) + goto done; + } + extent.e_pblk++; + extent.e_lblk++; + extent.e_len--; + retval = ext2fs_extent_replace(handle, 0, &extent); + if (retval) + goto done; + retval = ext2fs_extent_fix_parents(handle); + if (retval) + goto done; + } else { + __u32 save_length; + blk64_t save_lblk; + struct ext2fs_extent save_extent; + errcode_t r2; + +#ifdef DEBUG + printf("(re/un)mapping in middle of extent\n"); +#endif + /* need to split this extent; later */ + save_lblk = extent.e_lblk; + save_length = extent.e_len; + save_extent = extent; + + /* shorten pre-split extent */ + extent.e_len = (logical - extent.e_lblk); + retval = ext2fs_extent_replace(handle, 0, &extent); + if (retval) + goto done; + /* insert our new extent, if any */ + if (physical) { + /* insert new extent after current */ + retval = ext2fs_extent_insert(handle, + EXT2_EXTENT_INSERT_AFTER, &newextent); + if (retval) { + r2 = ext2fs_extent_goto(handle, save_lblk); + if (r2 == 0) + (void)ext2fs_extent_replace(handle, 0, + &save_extent); + goto done; + } + } + /* add post-split extent */ + extent.e_pblk += extent.e_len + 1; + extent.e_lblk += extent.e_len + 1; + extent.e_len = save_length - extent.e_len - 1; + retval = ext2fs_extent_insert(handle, + EXT2_EXTENT_INSERT_AFTER, &extent); + if (retval) { + if (physical) { + r2 = ext2fs_extent_goto(handle, + newextent.e_lblk); + if (r2 == 0) + (void)ext2fs_extent_delete(handle, 0); + } + r2 = ext2fs_extent_goto(handle, save_lblk); + if (r2 == 0) + (void)ext2fs_extent_replace(handle, 0, + &save_extent); + goto done; + } + } + +done: + /* get handle back to its position */ + if (orig_height > handle->max_depth) + orig_height = handle->max_depth; /* In case we shortened the tree */ + ext2fs_extent_goto2(handle, orig_height, orig_lblk); + return retval; +} + +errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, int flags) +{ + struct extent_path *path; + char *cp; + struct ext3_extent_header *eh; + errcode_t retval = 0; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + + if (!(handle->fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + if (!handle->path) + return EXT2_ET_NO_CURRENT_NODE; + +#ifdef DEBUG + { + struct ext2fs_extent extent; + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, + &extent); + if (retval == 0) { + printf("extent delete %u ", handle->ino); + dbg_print_extent(0, &extent); + } + } +#endif + + path = handle->path + handle->level; + if (!path->curr) + return EXT2_ET_NO_CURRENT_NODE; + + cp = path->curr; + + if (path->left) { + memmove(cp, cp + sizeof(struct ext3_extent_idx), + path->left * sizeof(struct ext3_extent_idx)); + path->left--; + } else { + struct ext3_extent_idx *ix = path->curr; + ix--; + path->curr = ix; + } + if (--path->entries == 0) + path->curr = 0; + + /* if non-root node has no entries left, remove it & parent ptr to it */ + if (path->entries == 0 && handle->level) { + if (!(flags & EXT2_EXTENT_DELETE_KEEP_EMPTY)) { + struct ext2fs_extent extent; + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, + &extent); + if (retval) + return retval; + + retval = ext2fs_extent_delete(handle, flags); + handle->inode->i_blocks -= + (handle->fs->blocksize * + EXT2FS_CLUSTER_RATIO(handle->fs)) / 512; + retval = ext2fs_write_inode(handle->fs, handle->ino, + handle->inode); + ext2fs_block_alloc_stats2(handle->fs, + extent.e_pblk, -1); + } + } else { + eh = (struct ext3_extent_header *) path->buf; + eh->eh_entries = ext2fs_cpu_to_le16(path->entries); + if ((path->entries == 0) && (handle->level == 0)) { + eh->eh_depth = 0; + handle->max_depth = 0; + } + retval = update_path(handle); + } + return retval; +} + +errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle, + struct ext2_extent_info *info) +{ + struct extent_path *path; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + + memset(info, 0, sizeof(struct ext2_extent_info)); + + path = handle->path + handle->level; + if (path) { + if (path->curr) + info->curr_entry = ((char *) path->curr - path->buf) / + sizeof(struct ext3_extent_idx); + else + info->curr_entry = 0; + info->num_entries = path->entries; + info->max_entries = path->max_entries; + info->bytes_avail = (path->max_entries - path->entries) * + sizeof(struct ext3_extent); + } + + info->curr_level = handle->level; + info->max_depth = handle->max_depth; + info->max_lblk = EXT_MAX_EXTENT_LBLK; + info->max_pblk = EXT_MAX_EXTENT_PBLK; + info->max_len = EXT_INIT_MAX_LEN; + info->max_uninit_len = EXT_UNINIT_MAX_LEN; + + return 0; +} + +static int ul_log2(unsigned long arg) +{ + int l = 0; + + arg >>= 1; + while (arg) { + l++; + arg >>= 1; + } + return l; +} + +size_t ext2fs_max_extent_depth(ext2_extent_handle_t handle) +{ + size_t iblock_sz = sizeof(((struct ext2_inode *)NULL)->i_block); + size_t iblock_extents = (iblock_sz - sizeof(struct ext3_extent_header)) / + sizeof(struct ext3_extent); + size_t extents_per_block = (handle->fs->blocksize - + sizeof(struct ext3_extent_header)) / + sizeof(struct ext3_extent); + static unsigned int last_blocksize = 0; + static size_t last_result = 0; + + if (last_blocksize && last_blocksize == handle->fs->blocksize) + return last_result; + + last_result = 1 + ((ul_log2(EXT_MAX_EXTENT_LBLK) - ul_log2(iblock_extents)) / + ul_log2(extents_per_block)); + last_blocksize = handle->fs->blocksize; + return last_result; +} + +#ifdef DEBUG +/* + * Override debugfs's prompt + */ +const char *debug_prog_name = "tst_extents"; + +#endif + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/fallocate.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/fallocate.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,855 @@ +/* + * fallocate.c -- Allocate large chunks of file. + * + * Copyright (C) 2014 Oracle. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" + +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#define min(a, b) ((a) < (b) ? (a) : (b)) + +#undef DEBUG + +#ifdef DEBUG +# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) +#else +# define dbg_printf(f, a...) +#endif + +/* + * Extent-based fallocate code. + * + * Find runs of unmapped logical blocks by starting at start and walking the + * extents until we reach the end of the range we want. + * + * For each run of unmapped blocks, try to find the extents on either side of + * the range. If there's a left extent that can grow by at least a cluster and + * there are lblocks between start and the next lcluster after start, see if + * there's an implied cluster allocation; if so, zero the blocks (if the left + * extent is initialized) and adjust the extent. Ditto for the blocks between + * the end of the last full lcluster and end, if there's a right extent. + * + * Try to attach as much as we can to the left extent, then try to attach as + * much as we can to the right extent. For the remainder, try to allocate the + * whole range; map in whatever we get; and repeat until we're done. + * + * To attach to a left extent, figure out the maximum amount we can add to the + * extent and try to allocate that much, and append if successful. To attach + * to a right extent, figure out the max we can add to the extent, try to + * allocate that much, and prepend if successful. + * + * We need an alloc_range function that tells us how much we can allocate given + * a maximum length and one of a suggested start, a fixed start, or a fixed end + * point. + * + * Every time we modify the extent tree we also need to update the block stats. + * + * At the end, update i_blocks and i_size appropriately. + */ + +static void dbg_print_extent(const char *desc EXT2FS_ATTR((unused)), + const struct ext2fs_extent *extent EXT2FS_ATTR((unused))) +{ +#ifdef DEBUG + if (desc) + printf("%s: ", desc); + printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ", + extent->e_lblk, extent->e_lblk + extent->e_len - 1, + extent->e_len, extent->e_pblk); + if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF) + fputs("LEAF ", stdout); + if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) + fputs("UNINIT ", stdout); + if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) + fputs("2ND_VISIT ", stdout); + if (!extent->e_flags) + fputs("(none)", stdout); + fputc('\n', stdout); + fflush(stdout); +#endif +} + +static errcode_t claim_range(ext2_filsys fs, struct ext2_inode *inode, + blk64_t blk, blk64_t len) +{ + blk64_t clusters; + + clusters = (len + EXT2FS_CLUSTER_RATIO(fs) - 1) / + EXT2FS_CLUSTER_RATIO(fs); + ext2fs_block_alloc_stats_range(fs, blk, + clusters * EXT2FS_CLUSTER_RATIO(fs), +1); + return ext2fs_iblk_add_blocks(fs, inode, clusters); +} + +static errcode_t ext_falloc_helper(ext2_filsys fs, + int flags, + ext2_ino_t ino, + struct ext2_inode *inode, + ext2_extent_handle_t handle, + struct ext2fs_extent *left_ext, + struct ext2fs_extent *right_ext, + blk64_t range_start, blk64_t range_len, + blk64_t alloc_goal) +{ + struct ext2fs_extent newex, ex; + int op; + blk64_t fillable, pblk, plen, x, y; + blk64_t eof_blk = 0, cluster_fill = 0; + errcode_t err; + blk_t max_extent_len, max_uninit_len, max_init_len; + +#ifdef DEBUG + printf("%s: ", __func__); + if (left_ext) + printf("left_ext=%llu--%llu, ", left_ext->e_lblk, + left_ext->e_lblk + left_ext->e_len - 1); + if (right_ext) + printf("right_ext=%llu--%llu, ", right_ext->e_lblk, + right_ext->e_lblk + right_ext->e_len - 1); + printf("start=%llu len=%llu, goal=%llu\n", range_start, range_len, + alloc_goal); + fflush(stdout); +#endif + /* Can't create initialized extents past EOF? */ + if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) + eof_blk = EXT2_I_SIZE(inode) / fs->blocksize; + + /* The allocation goal must be as far into a cluster as range_start. */ + alloc_goal = (alloc_goal & ~EXT2FS_CLUSTER_MASK(fs)) | + (range_start & EXT2FS_CLUSTER_MASK(fs)); + + max_uninit_len = EXT_UNINIT_MAX_LEN & ~EXT2FS_CLUSTER_MASK(fs); + max_init_len = EXT_INIT_MAX_LEN & ~EXT2FS_CLUSTER_MASK(fs); + + /* We must lengthen the left extent to the end of the cluster */ + if (left_ext && EXT2FS_CLUSTER_RATIO(fs) > 1) { + /* How many more blocks can be attached to left_ext? */ + if (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) + fillable = max_uninit_len - left_ext->e_len; + else + fillable = max_init_len - left_ext->e_len; + + if (fillable > range_len) + fillable = range_len; + if (fillable == 0) + goto expand_right; + + /* + * If range_start isn't on a cluster boundary, try an + * implied cluster allocation for left_ext. + */ + cluster_fill = EXT2FS_CLUSTER_RATIO(fs) - + (range_start & EXT2FS_CLUSTER_MASK(fs)); + cluster_fill &= EXT2FS_CLUSTER_MASK(fs); + if (cluster_fill == 0) + goto expand_right; + + if (cluster_fill > fillable) + cluster_fill = fillable; + + /* Don't expand an initialized left_ext beyond EOF */ + if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) { + x = left_ext->e_lblk + left_ext->e_len - 1; + dbg_printf("%s: lend=%llu newlend=%llu eofblk=%llu\n", + __func__, x, x + cluster_fill, eof_blk); + if (eof_blk >= x && eof_blk <= x + cluster_fill) + cluster_fill = eof_blk - x; + if (cluster_fill == 0) + goto expand_right; + } + + err = ext2fs_extent_goto(handle, left_ext->e_lblk); + if (err) + goto expand_right; + left_ext->e_len += cluster_fill; + range_start += cluster_fill; + range_len -= cluster_fill; + alloc_goal += cluster_fill; + + dbg_print_extent("ext_falloc clus left+", left_ext); + err = ext2fs_extent_replace(handle, 0, left_ext); + if (err) + goto out; + err = ext2fs_extent_fix_parents(handle); + if (err) + goto out; + + /* Zero blocks */ + if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) { + err = ext2fs_zero_blocks2(fs, left_ext->e_pblk + + left_ext->e_len - + cluster_fill, cluster_fill, + NULL, NULL); + if (err) + goto out; + } + } + +expand_right: + /* We must lengthen the right extent to the beginning of the cluster */ + if (right_ext && EXT2FS_CLUSTER_RATIO(fs) > 1) { + /* How much can we attach to right_ext? */ + if (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) + fillable = max_uninit_len - right_ext->e_len; + else + fillable = max_init_len - right_ext->e_len; + + if (fillable > range_len) + fillable = range_len; + if (fillable == 0) + goto try_merge; + + /* + * If range_end isn't on a cluster boundary, try an implied + * cluster allocation for right_ext. + */ + cluster_fill = right_ext->e_lblk & EXT2FS_CLUSTER_MASK(fs); + if (cluster_fill == 0) + goto try_merge; + + err = ext2fs_extent_goto(handle, right_ext->e_lblk); + if (err) + goto out; + + if (cluster_fill > fillable) + cluster_fill = fillable; + right_ext->e_lblk -= cluster_fill; + right_ext->e_pblk -= cluster_fill; + right_ext->e_len += cluster_fill; + range_len -= cluster_fill; + + dbg_print_extent("ext_falloc clus right+", right_ext); + err = ext2fs_extent_replace(handle, 0, right_ext); + if (err) + goto out; + err = ext2fs_extent_fix_parents(handle); + if (err) + goto out; + + /* Zero blocks if necessary */ + if (!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) { + err = ext2fs_zero_blocks2(fs, right_ext->e_pblk, + cluster_fill, NULL, NULL); + if (err) + goto out; + } + } + +try_merge: + /* Merge both extents together, perhaps? */ + if (left_ext && right_ext) { + /* Are the two extents mergeable? */ + if ((left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) != + (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) + goto try_left; + + /* User requires init/uninit but extent is uninit/init. */ + if (((flags & EXT2_FALLOCATE_FORCE_INIT) && + (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) || + ((flags & EXT2_FALLOCATE_FORCE_UNINIT) && + !(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT))) + goto try_left; + + /* + * Skip initialized extent unless user wants to zero blocks + * or requires init extent. + */ + if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) && + (!(flags & EXT2_FALLOCATE_ZERO_BLOCKS) || + !(flags & EXT2_FALLOCATE_FORCE_INIT))) + goto try_left; + + /* Will it even fit? */ + x = left_ext->e_len + range_len + right_ext->e_len; + if (x > (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT ? + max_uninit_len : max_init_len)) + goto try_left; + + err = ext2fs_extent_goto(handle, left_ext->e_lblk); + if (err) + goto try_left; + + /* Allocate blocks */ + y = left_ext->e_pblk + left_ext->e_len; + err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL | + EXT2_NEWRANGE_MIN_LENGTH, y, + right_ext->e_pblk - y + 1, NULL, + &pblk, &plen); + if (err) + goto try_left; + if (pblk + plen != right_ext->e_pblk) + goto try_left; + err = claim_range(fs, inode, pblk, plen); + if (err) + goto out; + + /* Modify extents */ + left_ext->e_len = x; + dbg_print_extent("ext_falloc merge", left_ext); + err = ext2fs_extent_replace(handle, 0, left_ext); + if (err) + goto out; + err = ext2fs_extent_fix_parents(handle); + if (err) + goto out; + err = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, &newex); + if (err) + goto out; + err = ext2fs_extent_delete(handle, 0); + if (err) + goto out; + err = ext2fs_extent_fix_parents(handle); + if (err) + goto out; + *right_ext = *left_ext; + + /* Zero blocks */ + if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) && + (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { + err = ext2fs_zero_blocks2(fs, range_start, range_len, + NULL, NULL); + if (err) + goto out; + } + + return 0; + } + +try_left: + /* Extend the left extent */ + if (left_ext) { + /* How many more blocks can be attached to left_ext? */ + if (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) + fillable = max_uninit_len - left_ext->e_len; + else if (flags & EXT2_FALLOCATE_ZERO_BLOCKS) + fillable = max_init_len - left_ext->e_len; + else + fillable = 0; + + /* User requires init/uninit but extent is uninit/init. */ + if (((flags & EXT2_FALLOCATE_FORCE_INIT) && + (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) || + ((flags & EXT2_FALLOCATE_FORCE_UNINIT) && + !(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT))) + goto try_right; + + if (fillable > range_len) + fillable = range_len; + + /* Don't expand an initialized left_ext beyond EOF */ + x = left_ext->e_lblk + left_ext->e_len - 1; + if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) { + dbg_printf("%s: lend=%llu newlend=%llu eofblk=%llu\n", + __func__, x, x + fillable, eof_blk); + if (eof_blk >= x && eof_blk <= x + fillable) + fillable = eof_blk - x; + } + + if (fillable == 0) + goto try_right; + + /* Test if the right edge of the range is already mapped? */ + if (EXT2FS_CLUSTER_RATIO(fs) > 1) { + err = ext2fs_map_cluster_block(fs, ino, inode, + x + fillable, &pblk); + if (err) + goto out; + if (pblk) + fillable -= 1 + ((x + fillable) + & EXT2FS_CLUSTER_MASK(fs)); + if (fillable == 0) + goto try_right; + } + + /* Allocate range of blocks */ + x = left_ext->e_pblk + left_ext->e_len; + err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL | + EXT2_NEWRANGE_MIN_LENGTH, + x, fillable, NULL, &pblk, &plen); + if (err) + goto try_right; + err = claim_range(fs, inode, pblk, plen); + if (err) + goto out; + + /* Modify left_ext */ + err = ext2fs_extent_goto(handle, left_ext->e_lblk); + if (err) + goto out; + range_start += plen; + range_len -= plen; + left_ext->e_len += plen; + dbg_print_extent("ext_falloc left+", left_ext); + err = ext2fs_extent_replace(handle, 0, left_ext); + if (err) + goto out; + err = ext2fs_extent_fix_parents(handle); + if (err) + goto out; + + /* Zero blocks if necessary */ + if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) && + (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { + err = ext2fs_zero_blocks2(fs, pblk, plen, NULL, NULL); + if (err) + goto out; + } + } + +try_right: + /* Extend the right extent */ + if (right_ext) { + /* How much can we attach to right_ext? */ + if (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) + fillable = max_uninit_len - right_ext->e_len; + else if (flags & EXT2_FALLOCATE_ZERO_BLOCKS) + fillable = max_init_len - right_ext->e_len; + else + fillable = 0; + + /* User requires init/uninit but extent is uninit/init. */ + if (((flags & EXT2_FALLOCATE_FORCE_INIT) && + (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) || + ((flags & EXT2_FALLOCATE_FORCE_UNINIT) && + !(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT))) + goto try_anywhere; + + if (fillable > range_len) + fillable = range_len; + if (fillable == 0) + goto try_anywhere; + + /* Test if the left edge of the range is already mapped? */ + if (EXT2FS_CLUSTER_RATIO(fs) > 1) { + err = ext2fs_map_cluster_block(fs, ino, inode, + right_ext->e_lblk - fillable, &pblk); + if (err) + goto out; + if (pblk) + fillable -= EXT2FS_CLUSTER_RATIO(fs) - + ((right_ext->e_lblk - fillable) + & EXT2FS_CLUSTER_MASK(fs)); + if (fillable == 0) + goto try_anywhere; + } + + /* + * FIXME: It would be nice if we could handle allocating a + * variable range from a fixed end point instead of just + * skipping to the general allocator if the whole range is + * unavailable. + */ + err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL | + EXT2_NEWRANGE_MIN_LENGTH, + right_ext->e_pblk - fillable, + fillable, NULL, &pblk, &plen); + if (err) + goto try_anywhere; + err = claim_range(fs, inode, + pblk & ~EXT2FS_CLUSTER_MASK(fs), + plen + (pblk & EXT2FS_CLUSTER_MASK(fs))); + if (err) + goto out; + + /* Modify right_ext */ + err = ext2fs_extent_goto(handle, right_ext->e_lblk); + if (err) + goto out; + range_len -= plen; + right_ext->e_lblk -= plen; + right_ext->e_pblk -= plen; + right_ext->e_len += plen; + dbg_print_extent("ext_falloc right+", right_ext); + err = ext2fs_extent_replace(handle, 0, right_ext); + if (err) + goto out; + err = ext2fs_extent_fix_parents(handle); + if (err) + goto out; + + /* Zero blocks if necessary */ + if (!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) && + (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { + err = ext2fs_zero_blocks2(fs, pblk, + plen + cluster_fill, NULL, NULL); + if (err) + goto out; + } + } + +try_anywhere: + /* Try implied cluster alloc on the left and right ends */ + if (range_len > 0 && (range_start & EXT2FS_CLUSTER_MASK(fs))) { + cluster_fill = EXT2FS_CLUSTER_RATIO(fs) - + (range_start & EXT2FS_CLUSTER_MASK(fs)); + cluster_fill &= EXT2FS_CLUSTER_MASK(fs); + if (cluster_fill > range_len) + cluster_fill = range_len; + newex.e_lblk = range_start; + err = ext2fs_map_cluster_block(fs, ino, inode, newex.e_lblk, + &pblk); + if (err) + goto out; + if (pblk == 0) + goto try_right_implied; + newex.e_pblk = pblk; + newex.e_len = cluster_fill; + newex.e_flags = (flags & EXT2_FALLOCATE_FORCE_INIT ? 0 : + EXT2_EXTENT_FLAGS_UNINIT); + dbg_print_extent("ext_falloc iclus left+", &newex); + ext2fs_extent_goto(handle, newex.e_lblk); + err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, + &ex); + if (err == EXT2_ET_NO_CURRENT_NODE) + ex.e_lblk = 0; + else if (err) + goto out; + + if (ex.e_lblk > newex.e_lblk) + op = 0; /* insert before */ + else + op = EXT2_EXTENT_INSERT_AFTER; + dbg_printf("%s: inserting %s lblk %llu newex=%llu\n", + __func__, op ? "after" : "before", ex.e_lblk, + newex.e_lblk); + err = ext2fs_extent_insert(handle, op, &newex); + if (err) + goto out; + err = ext2fs_extent_fix_parents(handle); + if (err) + goto out; + + if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && + (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { + err = ext2fs_zero_blocks2(fs, newex.e_pblk, + newex.e_len, NULL, NULL); + if (err) + goto out; + } + + range_start += cluster_fill; + range_len -= cluster_fill; + } + +try_right_implied: + y = range_start + range_len; + if (range_len > 0 && (y & EXT2FS_CLUSTER_MASK(fs))) { + cluster_fill = y & EXT2FS_CLUSTER_MASK(fs); + if (cluster_fill > range_len) + cluster_fill = range_len; + newex.e_lblk = y & ~EXT2FS_CLUSTER_MASK(fs); + err = ext2fs_map_cluster_block(fs, ino, inode, newex.e_lblk, + &pblk); + if (err) + goto out; + if (pblk == 0) + goto no_implied; + newex.e_pblk = pblk; + newex.e_len = cluster_fill; + newex.e_flags = (flags & EXT2_FALLOCATE_FORCE_INIT ? 0 : + EXT2_EXTENT_FLAGS_UNINIT); + dbg_print_extent("ext_falloc iclus right+", &newex); + ext2fs_extent_goto(handle, newex.e_lblk); + err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, + &ex); + if (err == EXT2_ET_NO_CURRENT_NODE) + ex.e_lblk = 0; + else if (err) + goto out; + + if (ex.e_lblk > newex.e_lblk) + op = 0; /* insert before */ + else + op = EXT2_EXTENT_INSERT_AFTER; + dbg_printf("%s: inserting %s lblk %llu newex=%llu\n", + __func__, op ? "after" : "before", ex.e_lblk, + newex.e_lblk); + err = ext2fs_extent_insert(handle, op, &newex); + if (err) + goto out; + err = ext2fs_extent_fix_parents(handle); + if (err) + goto out; + + if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && + (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { + err = ext2fs_zero_blocks2(fs, newex.e_pblk, + newex.e_len, NULL, NULL); + if (err) + goto out; + } + + range_len -= cluster_fill; + } + +no_implied: + if (range_len == 0) + return 0; + + newex.e_lblk = range_start; + if (flags & EXT2_FALLOCATE_FORCE_INIT) { + max_extent_len = max_init_len; + newex.e_flags = 0; + } else { + max_extent_len = max_uninit_len; + newex.e_flags = EXT2_EXTENT_FLAGS_UNINIT; + } + pblk = alloc_goal; + y = range_len; + for (x = 0; x < y;) { + cluster_fill = newex.e_lblk & EXT2FS_CLUSTER_MASK(fs); + fillable = min(range_len + cluster_fill, max_extent_len); + err = ext2fs_new_range(fs, 0, pblk & ~EXT2FS_CLUSTER_MASK(fs), + fillable, + NULL, &pblk, &plen); + if (err) + goto out; + err = claim_range(fs, inode, pblk, plen); + if (err) + goto out; + + /* Create extent */ + newex.e_pblk = pblk + cluster_fill; + newex.e_len = plen - cluster_fill; + dbg_print_extent("ext_falloc create", &newex); + ext2fs_extent_goto(handle, newex.e_lblk); + err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, + &ex); + if (err == EXT2_ET_NO_CURRENT_NODE) + ex.e_lblk = 0; + else if (err) + goto out; + + if (ex.e_lblk > newex.e_lblk) + op = 0; /* insert before */ + else + op = EXT2_EXTENT_INSERT_AFTER; + dbg_printf("%s: inserting %s lblk %llu newex=%llu\n", + __func__, op ? "after" : "before", ex.e_lblk, + newex.e_lblk); + err = ext2fs_extent_insert(handle, op, &newex); + if (err) + goto out; + err = ext2fs_extent_fix_parents(handle); + if (err) + goto out; + + if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && + (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { + err = ext2fs_zero_blocks2(fs, pblk, plen, NULL, NULL); + if (err) + goto out; + } + + /* Update variables at end of loop */ + x += plen - cluster_fill; + range_len -= plen - cluster_fill; + newex.e_lblk += plen - cluster_fill; + pblk += plen - cluster_fill; + if (pblk >= ext2fs_blocks_count(fs->super)) + pblk = fs->super->s_first_data_block; + } + +out: + return err; +} + +static errcode_t extent_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t goal, + blk64_t start, blk64_t len) +{ + ext2_extent_handle_t handle; + struct ext2fs_extent left_extent, right_extent; + struct ext2fs_extent *left_adjacent, *right_adjacent; + errcode_t err; + blk64_t range_start, range_end = 0, end, next; + blk64_t count, goal_distance; + + end = start + len - 1; + err = ext2fs_extent_open2(fs, ino, inode, &handle); + if (err) + return err; + + /* + * Find the extent closest to the start of the alloc range. We don't + * check the return value because _goto() sets the current node to the + * next-lowest extent if 'start' is in a hole; or the next-highest + * extent if there aren't any lower ones; or doesn't set a current node + * if there was a real error reading the extent tree. In that case, + * _get() will error out. + */ +start_again: + ext2fs_extent_goto(handle, start); + err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &left_extent); + if (err == EXT2_ET_NO_CURRENT_NODE) { + blk64_t max_blocks = ext2fs_blocks_count(fs->super); + + if (goal == ~0ULL) + goal = ext2fs_find_inode_goal(fs, ino, inode, start); + err = ext2fs_find_first_zero_block_bitmap2(fs->block_map, + goal, max_blocks - 1, &goal); + goal += start; + err = ext_falloc_helper(fs, flags, ino, inode, handle, NULL, + NULL, start, len, goal); + goto errout; + } else if (err) + goto errout; + + dbg_print_extent("ext_falloc initial", &left_extent); + next = left_extent.e_lblk + left_extent.e_len; + if (left_extent.e_lblk > start) { + /* The nearest extent we found was beyond start??? */ + goal = left_extent.e_pblk - (left_extent.e_lblk - start); + err = ext_falloc_helper(fs, flags, ino, inode, handle, NULL, + &left_extent, start, + left_extent.e_lblk - start, goal); + if (err) + goto errout; + + goto start_again; + } else if (next >= start) { + range_start = next; + left_adjacent = &left_extent; + } else { + range_start = start; + left_adjacent = NULL; + } + goal = left_extent.e_pblk + (range_start - left_extent.e_lblk); + + do { + err = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, + &right_extent); + dbg_printf("%s: ino=%d get next =%d\n", __func__, ino, + (int)err); + dbg_print_extent("ext_falloc next", &right_extent); + /* Stop if we've seen this extent before */ + if (!err && right_extent.e_lblk <= left_extent.e_lblk) + err = EXT2_ET_EXTENT_NO_NEXT; + + if (err && err != EXT2_ET_EXTENT_NO_NEXT) + goto errout; + if (err == EXT2_ET_EXTENT_NO_NEXT || + right_extent.e_lblk > end + 1) { + range_end = end; + right_adjacent = NULL; + } else { + /* Handle right_extent.e_lblk <= end */ + range_end = right_extent.e_lblk - 1; + right_adjacent = &right_extent; + } + goal_distance = range_start - next; + if (err != EXT2_ET_EXTENT_NO_NEXT && + goal_distance > (range_end - right_extent.e_lblk)) + goal = right_extent.e_pblk - + (right_extent.e_lblk - range_start); + + dbg_printf("%s: ino=%d rstart=%llu rend=%llu\n", __func__, ino, + range_start, range_end); + err = 0; + if (range_start <= range_end) { + count = range_end - range_start + 1; + err = ext_falloc_helper(fs, flags, ino, inode, handle, + left_adjacent, right_adjacent, + range_start, count, goal); + if (err) + goto errout; + } + + if (range_end == end) + break; + + err = ext2fs_extent_goto(handle, right_extent.e_lblk); + if (err) + goto errout; + next = right_extent.e_lblk + right_extent.e_len; + left_extent = right_extent; + left_adjacent = &left_extent; + range_start = next; + goal = left_extent.e_pblk + (range_start - left_extent.e_lblk); + } while (range_end < end); + +errout: + ext2fs_extent_free(handle); + return err; +} + +/* + * Map physical blocks to a range of logical blocks within a file. The range + * of logical blocks are (start, start + len). If there are already extents, + * the mappings will try to extend the mappings; otherwise, it will try to map + * start as if logical block 0 points to goal. If goal is ~0ULL, then the goal + * is calculated based on the inode group. + * + * Flags: + * - EXT2_FALLOCATE_ZERO_BLOCKS: Zero the blocks that are allocated. + * - EXT2_FALLOCATE_FORCE_INIT: Create only initialized extents. + * - EXT2_FALLOCATE_FORCE_UNINIT: Create only uninitialized extents. + * - EXT2_FALLOCATE_INIT_BEYOND_EOF: Create extents beyond EOF. + * + * If neither FORCE_INIT nor FORCE_UNINIT are specified, this function will + * try to expand any extents it finds, zeroing blocks as necessary. + */ +errcode_t ext2fs_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t goal, + blk64_t start, blk64_t len) +{ + struct ext2_inode inode_buf; + blk64_t blk, x; + errcode_t err; + + if (((flags & EXT2_FALLOCATE_FORCE_INIT) && + (flags & EXT2_FALLOCATE_FORCE_UNINIT)) || + (flags & ~EXT2_FALLOCATE_ALL_FLAGS)) + return EXT2_ET_INVALID_ARGUMENT; + + if (len > ext2fs_blocks_count(fs->super)) + return EXT2_ET_BLOCK_ALLOC_FAIL; + else if (len == 0) + return 0; + + /* Read inode structure if necessary */ + if (!inode) { + err = ext2fs_read_inode(fs, ino, &inode_buf); + if (err) + return err; + inode = &inode_buf; + } + dbg_printf("%s: ino=%d start=%llu len=%llu goal=%llu\n", __func__, ino, + start, len, goal); + + if (inode->i_flags & EXT4_EXTENTS_FL) { + err = extent_fallocate(fs, flags, ino, inode, goal, start, len); + goto out; + } + + /* XXX: Allocate a bunch of blocks the slow way */ + for (blk = start; blk < start + len; blk++) { + err = ext2fs_bmap2(fs, ino, inode, NULL, 0, blk, 0, &x); + if (err) + return err; + if (x) + continue; + + err = ext2fs_bmap2(fs, ino, inode, NULL, + BMAP_ALLOC | BMAP_UNINIT | BMAP_ZERO, blk, + 0, &x); + if (err) + return err; + } + +out: + if (inode == &inode_buf) + ext2fs_write_inode(fs, ino, inode); + return err; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/fiemap.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/fiemap.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,77 @@ +/* + * FS_IOC_FIEMAP ioctl infrastructure. + * + * Some portions copyright (C) 2007 Cluster File Systems, Inc + * + * Authors: Mark Fasheh + * Kalpak Shah + * Andreas Dilger + */ + +#ifndef _LINUX_FIEMAP_H +#define _LINUX_FIEMAP_H + +struct fiemap_extent { + __u64 fe_logical; /* logical offset in bytes for the start of + * the extent from the beginning of the file */ + __u64 fe_physical; /* physical offset in bytes for the start + * of the extent from the beginning of the disk */ + __u64 fe_length; /* length in bytes for this extent */ + __u64 fe_reserved64[2]; + __u32 fe_flags; /* FIEMAP_EXTENT_* flags for this extent */ + __u32 fe_reserved[3]; +}; + +struct fiemap { + __u64 fm_start; /* logical offset (inclusive) at + * which to start mapping (in) */ + __u64 fm_length; /* logical length of mapping which + * userspace wants (in) */ + __u32 fm_flags; /* FIEMAP_FLAG_* flags for request (in/out) */ + __u32 fm_mapped_extents;/* number of extents that were mapped (out) */ + __u32 fm_extent_count; /* size of fm_extents array (in) */ + __u32 fm_reserved; +#if __GNUC_PREREQ (4, 8) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#endif + struct fiemap_extent fm_extents[0]; /* array of mapped extents (out) */ +#if __GNUC_PREREQ (4, 8) +#pragma GCC diagnostic pop +#endif +}; + +#if defined(__linux__) && !defined(FS_IOC_FIEMAP) +#define FS_IOC_FIEMAP _IOWR('f', 11, struct fiemap) +#endif + +#define FIEMAP_MAX_OFFSET (~0ULL) + +#define FIEMAP_FLAG_SYNC 0x00000001 /* sync file data before map */ +#define FIEMAP_FLAG_XATTR 0x00000002 /* map extended attribute tree */ + +#define FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR) + +#define FIEMAP_EXTENT_LAST 0x00000001 /* Last extent in file. */ +#define FIEMAP_EXTENT_UNKNOWN 0x00000002 /* Data location unknown. */ +#define FIEMAP_EXTENT_DELALLOC 0x00000004 /* Location still pending. + * Sets EXTENT_UNKNOWN. */ +#define FIEMAP_EXTENT_ENCODED 0x00000008 /* Data can not be read + * while fs is unmounted */ +#define FIEMAP_EXTENT_DATA_ENCRYPTED 0x00000080 /* Data is encrypted by fs. + * Sets EXTENT_NO_BYPASS. */ +#define FIEMAP_EXTENT_NOT_ALIGNED 0x00000100 /* Extent offsets may not be + * block aligned. */ +#define FIEMAP_EXTENT_DATA_INLINE 0x00000200 /* Data mixed with metadata. + * Sets EXTENT_NOT_ALIGNED.*/ +#define FIEMAP_EXTENT_DATA_TAIL 0x00000400 /* Multiple files in block. + * Sets EXTENT_NOT_ALIGNED.*/ +#define FIEMAP_EXTENT_UNWRITTEN 0x00000800 /* Space allocated, but + * no data (i.e. zero). */ +#define FIEMAP_EXTENT_MERGED 0x00001000 /* File does not natively + * support extents. Result + * merged for efficiency. */ +#define FIEMAP_EXTENT_SHARED 0x00002000 /* Space shared with other + * files. */ + +#endif /* _LINUX_FIEMAP_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/fileio.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/fileio.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,660 @@ +/* + * fileio.c --- Simple file I/O routines + * + * Copyright (C) 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +struct ext2_file { + errcode_t magic; + ext2_filsys fs; + ext2_ino_t ino; + struct ext2_inode inode; + int flags; + __u64 pos; + blk64_t blockno; + blk64_t physblock; + char *buf; +}; + +struct block_entry { + blk64_t physblock; + unsigned char sha[EXT2FS_SHA512_LENGTH]; +}; +typedef struct block_entry *block_entry_t; + +#define BMAP_BUFFER (file->buf + fs->blocksize) + +errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + int flags, ext2_file_t *ret) +{ + ext2_file_t file; + errcode_t retval; + + /* + * Don't let caller create or open a file for writing if the + * filesystem is read-only. + */ + if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) && + !(fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + retval = ext2fs_get_mem(sizeof(struct ext2_file), &file); + if (retval) + return retval; + + memset(file, 0, sizeof(struct ext2_file)); + file->magic = EXT2_ET_MAGIC_EXT2_FILE; + file->fs = fs; + file->ino = ino; + file->flags = flags & EXT2_FILE_MASK; + + if (inode) { + memcpy(&file->inode, inode, sizeof(struct ext2_inode)); + } else { + retval = ext2fs_read_inode(fs, ino, &file->inode); + if (retval) + goto fail; + } + + retval = ext2fs_get_array(3, fs->blocksize, &file->buf); + if (retval) + goto fail; + + *ret = file; + return 0; + +fail: + if (file->buf) + ext2fs_free_mem(&file->buf); + ext2fs_free_mem(&file); + return retval; +} + +errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino, + int flags, ext2_file_t *ret) +{ + return ext2fs_file_open2(fs, ino, NULL, flags, ret); +} + +/* + * This function returns the filesystem handle of a file from the structure + */ +ext2_filsys ext2fs_file_get_fs(ext2_file_t file) +{ + if (file->magic != EXT2_ET_MAGIC_EXT2_FILE) + return 0; + return file->fs; +} + +/* + * This function returns the pointer to the inode of a file from the structure + */ +struct ext2_inode *ext2fs_file_get_inode(ext2_file_t file) +{ + if (file->magic != EXT2_ET_MAGIC_EXT2_FILE) + return NULL; + return &file->inode; +} + +/* This function returns the inode number from the structure */ +ext2_ino_t ext2fs_file_get_inode_num(ext2_file_t file) +{ + if (file->magic != EXT2_ET_MAGIC_EXT2_FILE) + return 0; + return file->ino; +} + +/* + * This function flushes the dirty block buffer out to disk if + * necessary. + */ +errcode_t ext2fs_file_flush(ext2_file_t file) +{ + errcode_t retval; + ext2_filsys fs; + int ret_flags; + blk64_t dontcare; + + EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); + fs = file->fs; + + if (!(file->flags & EXT2_FILE_BUF_VALID) || + !(file->flags & EXT2_FILE_BUF_DIRTY)) + return 0; + + /* Is this an uninit block? */ + if (file->physblock && file->inode.i_flags & EXT4_EXTENTS_FL) { + retval = ext2fs_bmap2(fs, file->ino, &file->inode, BMAP_BUFFER, + 0, file->blockno, &ret_flags, &dontcare); + if (retval) + return retval; + if (ret_flags & BMAP_RET_UNINIT) { + retval = ext2fs_bmap2(fs, file->ino, &file->inode, + BMAP_BUFFER, BMAP_SET, + file->blockno, 0, + &file->physblock); + if (retval) + return retval; + } + } + + /* + * OK, the physical block hasn't been allocated yet. + * Allocate it. + */ + if (!file->physblock) { + retval = ext2fs_bmap2(fs, file->ino, &file->inode, + BMAP_BUFFER, file->ino ? BMAP_ALLOC : 0, + file->blockno, 0, &file->physblock); + if (retval) + return retval; + } + + retval = io_channel_write_blk64(fs->io, file->physblock, 1, file->buf); + if (retval) + return retval; + + file->flags &= ~EXT2_FILE_BUF_DIRTY; + + return retval; +} + +/* + * This function synchronizes the file's block buffer and the current + * file position, possibly invalidating block buffer if necessary + */ +static errcode_t sync_buffer_position(ext2_file_t file) +{ + blk64_t b; + errcode_t retval; + + b = file->pos / file->fs->blocksize; + if (b != file->blockno) { + retval = ext2fs_file_flush(file); + if (retval) + return retval; + file->flags &= ~EXT2_FILE_BUF_VALID; + } + file->blockno = b; + return 0; +} + +/* + * This function loads the file's block buffer with valid data from + * the disk as necessary. + * + * If dontfill is true, then skip initializing the buffer since we're + * going to be replacing its entire contents anyway. If set, then the + * function basically only sets file->physblock and EXT2_FILE_BUF_VALID + */ +#define DONTFILL 1 +static errcode_t load_buffer(ext2_file_t file, int dontfill) +{ + ext2_filsys fs = file->fs; + errcode_t retval; + int ret_flags; + + if (!(file->flags & EXT2_FILE_BUF_VALID)) { + retval = ext2fs_bmap2(fs, file->ino, &file->inode, + BMAP_BUFFER, 0, file->blockno, &ret_flags, + &file->physblock); + if (retval) + return retval; + if (!dontfill) { + if (file->physblock && + !(ret_flags & BMAP_RET_UNINIT)) { + retval = io_channel_read_blk64(fs->io, + file->physblock, + 1, file->buf); + if (retval) + return retval; + } else + memset(file->buf, 0, fs->blocksize); + } + file->flags |= EXT2_FILE_BUF_VALID; + } + return 0; +} + + +errcode_t ext2fs_file_close(ext2_file_t file) +{ + errcode_t retval; + + EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); + + retval = ext2fs_file_flush(file); + + if (file->buf) + ext2fs_free_mem(&file->buf); + ext2fs_free_mem(&file); + + return retval; +} + + +static errcode_t +ext2fs_file_read_inline_data(ext2_file_t file, void *buf, + unsigned int wanted, unsigned int *got) +{ + ext2_filsys fs; + errcode_t retval; + unsigned int count = 0; + size_t size; + + fs = file->fs; + retval = ext2fs_inline_data_get(fs, file->ino, &file->inode, + file->buf, &size); + if (retval) + return retval; + + if (file->pos >= size) + goto out; + + count = size - file->pos; + if (count > wanted) + count = wanted; + memcpy(buf, file->buf + file->pos, count); + file->pos += count; + buf = (char *) buf + count; + +out: + if (got) + *got = count; + return retval; +} + + +errcode_t ext2fs_file_read(ext2_file_t file, void *buf, + unsigned int wanted, unsigned int *got) +{ + ext2_filsys fs; + errcode_t retval = 0; + unsigned int start, c, count = 0; + __u64 left; + char *ptr = (char *) buf; + + EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); + fs = file->fs; + + /* If an inode has inline data, things get complicated. */ + if (file->inode.i_flags & EXT4_INLINE_DATA_FL) + return ext2fs_file_read_inline_data(file, buf, wanted, got); + + while ((file->pos < EXT2_I_SIZE(&file->inode)) && (wanted > 0)) { + retval = sync_buffer_position(file); + if (retval) + goto fail; + retval = load_buffer(file, 0); + if (retval) + goto fail; + + start = file->pos % fs->blocksize; + c = fs->blocksize - start; + if (c > wanted) + c = wanted; + left = EXT2_I_SIZE(&file->inode) - file->pos ; + if (c > left) + c = left; + + memcpy(ptr, file->buf+start, c); + file->pos += c; + ptr += c; + count += c; + wanted -= c; + } + +fail: + if (got) + *got = count; + return retval; +} + + +static errcode_t +ext2fs_file_write_inline_data(ext2_file_t file, const void *buf, + unsigned int nbytes, unsigned int *written) +{ + ext2_filsys fs; + errcode_t retval; + unsigned int count = 0; + size_t size; + + fs = file->fs; + retval = ext2fs_inline_data_get(fs, file->ino, &file->inode, + file->buf, &size); + if (retval) + return retval; + + if (file->pos < size) { + count = nbytes - file->pos; + memcpy(file->buf + file->pos, buf, count); + + retval = ext2fs_inline_data_set(fs, file->ino, &file->inode, + file->buf, count); + if (retval == EXT2_ET_INLINE_DATA_NO_SPACE) + goto expand; + if (retval) + return retval; + + file->pos += count; + + /* Update inode size */ + if (count != 0 && EXT2_I_SIZE(&file->inode) < file->pos) { + errcode_t rc; + + rc = ext2fs_file_set_size2(file, file->pos); + if (retval == 0) + retval = rc; + } + + if (written) + *written = count; + return 0; + } + +expand: + retval = ext2fs_inline_data_expand(fs, file->ino); + if (retval) + return retval; + /* + * reload inode and return no space error + * + * XXX: file->inode could be copied from the outside + * in ext2fs_file_open2(). We have no way to modify + * the outside inode. + */ + retval = ext2fs_read_inode(fs, file->ino, &file->inode); + if (retval) + return retval; + return EXT2_ET_INLINE_DATA_NO_SPACE; +} + + +errcode_t ext2fs_file_write(ext2_file_t file, const void *buf, + unsigned int nbytes, unsigned int *written) +{ + ext2_filsys fs; + errcode_t retval = 0; + unsigned int start, c, count = 0; + const char *ptr = (const char *) buf; + block_entry_t new_block = NULL, old_block = NULL; + int bmap_flags = 0; + + EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); + fs = file->fs; + + if (!(file->flags & EXT2_FILE_WRITE)) + return EXT2_ET_FILE_RO; + + /* If an inode has inline data, things get complicated. */ + if (file->inode.i_flags & EXT4_INLINE_DATA_FL) { + retval = ext2fs_file_write_inline_data(file, buf, nbytes, + written); + if (retval != EXT2_ET_INLINE_DATA_NO_SPACE) + return retval; + /* fall through to read data from the block */ + retval = 0; + } + + while (nbytes > 0) { + retval = sync_buffer_position(file); + if (retval) + goto fail; + + start = file->pos % fs->blocksize; + c = fs->blocksize - start; + if (c > nbytes) + c = nbytes; + + /* + * We only need to do a read-modify-update cycle if + * we're doing a partial write. + */ + retval = load_buffer(file, (c == fs->blocksize)); + if (retval) + goto fail; + + file->flags |= EXT2_FILE_BUF_DIRTY; + memcpy(file->buf+start, ptr, c); + + /* + * OK, the physical block hasn't been allocated yet. + * Allocate it. + */ + if (!file->physblock) { + bmap_flags = (file->ino ? BMAP_ALLOC : 0); + if (fs->flags & EXT2_FLAG_SHARE_DUP) { + new_block = calloc(1, sizeof(*new_block)); + if (!new_block) { + retval = EXT2_ET_NO_MEMORY; + goto fail; + } + ext2fs_sha512((const unsigned char*)file->buf, + fs->blocksize, new_block->sha); + old_block = ext2fs_hashmap_lookup( + fs->block_sha_map, + new_block->sha, + sizeof(new_block->sha)); + } + + if (old_block) { + file->physblock = old_block->physblock; + bmap_flags |= BMAP_SET; + free(new_block); + new_block = NULL; + } + + retval = ext2fs_bmap2(fs, file->ino, &file->inode, + BMAP_BUFFER, + bmap_flags, + file->blockno, 0, + &file->physblock); + if (retval) { + free(new_block); + new_block = NULL; + goto fail; + } + + if (new_block) { + new_block->physblock = file->physblock; + ext2fs_hashmap_add(fs->block_sha_map, new_block, + new_block->sha, sizeof(new_block->sha)); + } + + if (bmap_flags & BMAP_SET) { + ext2fs_iblk_add_blocks(fs, &file->inode, 1); + ext2fs_write_inode(fs, file->ino, &file->inode); + } + } + + file->pos += c; + ptr += c; + count += c; + nbytes -= c; + } + +fail: + /* Update inode size */ + if (count != 0 && EXT2_I_SIZE(&file->inode) < file->pos) { + errcode_t rc; + + rc = ext2fs_file_set_size2(file, file->pos); + if (retval == 0) + retval = rc; + } + + if (written) + *written = count; + return retval; +} + +errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset, + int whence, __u64 *ret_pos) +{ + EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); + + if (whence == EXT2_SEEK_SET) + file->pos = offset; + else if (whence == EXT2_SEEK_CUR) + file->pos += offset; + else if (whence == EXT2_SEEK_END) + file->pos = EXT2_I_SIZE(&file->inode) + offset; + else + return EXT2_ET_INVALID_ARGUMENT; + + if (ret_pos) + *ret_pos = file->pos; + + return 0; +} + +errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset, + int whence, ext2_off_t *ret_pos) +{ + __u64 loffset, ret_loffset = 0; + errcode_t retval; + + loffset = offset; + retval = ext2fs_file_llseek(file, loffset, whence, &ret_loffset); + if (ret_pos) + *ret_pos = (ext2_off_t) ret_loffset; + return retval; +} + + +/* + * This function returns the size of the file, according to the inode + */ +errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size) +{ + if (file->magic != EXT2_ET_MAGIC_EXT2_FILE) + return EXT2_ET_MAGIC_EXT2_FILE; + *ret_size = EXT2_I_SIZE(&file->inode); + return 0; +} + +/* + * This function returns the size of the file, according to the inode + */ +ext2_off_t ext2fs_file_get_size(ext2_file_t file) +{ + __u64 size; + + if (ext2fs_file_get_lsize(file, &size)) + return 0; + if ((size >> 32) != 0) + return 0; + return size; +} + +/* Zero the parts of the last block that are past EOF. */ +static errcode_t ext2fs_file_zero_past_offset(ext2_file_t file, + ext2_off64_t offset) +{ + ext2_filsys fs = file->fs; + char *b = NULL; + ext2_off64_t off = offset % fs->blocksize; + blk64_t blk; + int ret_flags; + errcode_t retval; + + if (off == 0) + return 0; + + retval = sync_buffer_position(file); + if (retval) + return retval; + + /* Is there an initialized block at the end? */ + retval = ext2fs_bmap2(fs, file->ino, NULL, NULL, 0, + offset / fs->blocksize, &ret_flags, &blk); + if (retval) + return retval; + if ((blk == 0) || (ret_flags & BMAP_RET_UNINIT)) + return 0; + + /* Zero to the end of the block */ + retval = ext2fs_get_mem(fs->blocksize, &b); + if (retval) + return retval; + + /* Read/zero/write block */ + retval = io_channel_read_blk64(fs->io, blk, 1, b); + if (retval) + goto out; + + memset(b + off, 0, fs->blocksize - off); + + retval = io_channel_write_blk64(fs->io, blk, 1, b); + if (retval) + goto out; + +out: + ext2fs_free_mem(&b); + return retval; +} + +/* + * This function sets the size of the file, truncating it if necessary + * + */ +errcode_t ext2fs_file_set_size2(ext2_file_t file, ext2_off64_t size) +{ + ext2_off64_t old_size; + errcode_t retval; + blk64_t old_truncate, truncate_block; + + EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); + + if (size && ext2fs_file_block_offset_too_big(file->fs, &file->inode, + (size - 1) / file->fs->blocksize)) + return EXT2_ET_FILE_TOO_BIG; + truncate_block = ((size + file->fs->blocksize - 1) >> + EXT2_BLOCK_SIZE_BITS(file->fs->super)); + old_size = EXT2_I_SIZE(&file->inode); + old_truncate = ((old_size + file->fs->blocksize - 1) >> + EXT2_BLOCK_SIZE_BITS(file->fs->super)); + + retval = ext2fs_inode_size_set(file->fs, &file->inode, size); + if (retval) + return retval; + + if (file->ino) { + retval = ext2fs_write_inode(file->fs, file->ino, &file->inode); + if (retval) + return retval; + } + + retval = ext2fs_file_zero_past_offset(file, size); + if (retval) + return retval; + + if (truncate_block >= old_truncate) + return 0; + + return ext2fs_punch(file->fs, file->ino, &file->inode, 0, + truncate_block, ~0ULL); +} + +errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size) +{ + return ext2fs_file_set_size2(file, size); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/finddev.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/finddev.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,218 @@ +/* + * finddev.c -- this routine attempts to find a particular device in + * /dev + * + * Copyright (C) 2000 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#include +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_SYS_MKDEV_H +#include +#endif +#ifdef HAVE_SYS_SYSMACROS_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +struct dir_list { + char *name; + struct dir_list *next; +}; + +/* + * This function adds an entry to the directory list + */ +static void add_to_dirlist(const char *name, struct dir_list **list) +{ + struct dir_list *dp; + + dp = malloc(sizeof(struct dir_list)); + if (!dp) + return; + dp->name = malloc(strlen(name)+1); + if (!dp->name) { + free(dp); + return; + } + strcpy(dp->name, name); + dp->next = *list; + *list = dp; +} + +/* + * This function frees a directory list + */ +static void free_dirlist(struct dir_list **list) +{ + struct dir_list *dp, *next; + + for (dp = *list; dp; dp = next) { + next = dp->next; + free(dp->name); + free(dp); + } + *list = 0; +} + +static int scan_dir(char *dirname, dev_t device, struct dir_list **list, + char **ret_path) +{ + DIR *dir; + struct dirent *dp; + char path[1024], *cp; + int dirlen; + struct stat st; + + dirlen = strlen(dirname); + if ((dir = opendir(dirname)) == NULL) + return errno; + dp = readdir(dir); + while (dp) { + if (dirlen + strlen(dp->d_name) + 2 >= sizeof(path)) + goto skip_to_next; + if (dp->d_name[0] == '.' && + ((dp->d_name[1] == 0) || + ((dp->d_name[1] == '.') && (dp->d_name[2] == 0)))) + goto skip_to_next; + sprintf(path, "%s/%s", dirname, dp->d_name); + if (stat(path, &st) < 0) + goto skip_to_next; + if (S_ISDIR(st.st_mode)) + add_to_dirlist(path, list); + if (ext2fsP_is_disk_device(st.st_mode) && + st.st_rdev == device) { + cp = malloc(strlen(path)+1); + if (!cp) { + closedir(dir); + return ENOMEM; + } + strcpy(cp, path); + *ret_path = cp; + goto success; + } + skip_to_next: + dp = readdir(dir); + } +success: + closedir(dir); + return 0; +} + +/* + * This function finds the pathname to a block device with a given + * device number. It returns a pointer to allocated memory to the + * pathname on success, and NULL on failure. + */ +char *ext2fs_find_block_device(dev_t device) +{ + struct dir_list *list = 0, *new_list = 0; + struct dir_list *current; + char *ret_path = 0; + int level = 0; + + /* + * Add the starting directories to search... + */ + add_to_dirlist("/devices", &list); + add_to_dirlist("/devfs", &list); + add_to_dirlist("/dev", &list); + + while (list) { + current = list; + list = list->next; +#ifdef DEBUG + printf("Scanning directory %s\n", current->name); +#endif + scan_dir(current->name, device, &new_list, &ret_path); + free(current->name); + free(current); + if (ret_path) + break; + /* + * If we're done checking at this level, descend to + * the next level of subdirectories. (breadth-first) + */ + if (list == 0) { + list = new_list; + new_list = 0; + /* Avoid infinite loop */ + if (++level >= EXT2FS_MAX_NESTED_LINKS) + break; + } + } + free_dirlist(&list); + free_dirlist(&new_list); + return ret_path; +} + + +#ifdef DEBUG +int main(int argc, char** argv) +{ + char *devname, *tmp; + int major, minor; + dev_t device; + const char *errmsg = "Couldn't parse %s: %s\n"; + + if ((argc != 2) && (argc != 3)) { + fprintf(stderr, "Usage: %s device_number\n", argv[0]); + fprintf(stderr, "\t: %s major minor\n", argv[0]); + exit(1); + } + if (argc == 2) { + device = strtoul(argv[1], &tmp, 0); + if (*tmp) { + fprintf(stderr, errmsg, "device number", argv[1]); + exit(1); + } + } else { + major = strtoul(argv[1], &tmp, 0); + if (*tmp) { + fprintf(stderr, errmsg, "major number", argv[1]); + exit(1); + } + minor = strtoul(argv[2], &tmp, 0); + if (*tmp) { + fprintf(stderr, errmsg, "minor number", argv[2]); + exit(1); + } + device = makedev(major, minor); + printf("Looking for device 0x%04x (%d:%d)\n", device, + major, minor); + } + devname = ext2fs_find_block_device(device); + if (devname) { + printf("Found device! %s\n", devname); + free(devname); + } else { + printf("Couldn't find device.\n"); + } + return 0; +} + +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/flushb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/flushb.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,88 @@ +/* + * flushb.c --- Hides system-dependent information for both syncing a + * device to disk and to flush any buffers from disk cache. + * + * Copyright (C) 2000 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_SYS_IOCTL_H +#include +#endif +#if HAVE_SYS_MOUNT_H +#include +#include /* This may define BLKFLSBUF */ +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +/* + * For Linux, define BLKFLSBUF and FDFLUSH if necessary, since + * not all portable header file does so for us. This really should be + * fixed in the glibc header files. (Recent glibcs appear to define + * BLKFLSBUF in sys/mount.h, but FDFLUSH still doesn't seem to be + * defined anywhere portable.) Until then.... + */ +#ifdef __linux__ +#ifndef BLKFLSBUF +#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */ +#endif +#ifndef FDFLUSH +#define FDFLUSH _IO(2,0x4b) /* flush floppy disk */ +#endif +#endif + +/* + * This function will sync a device/file, and optionally attempt to + * flush the buffer cache. The latter is basically only useful for + * system benchmarks and for torturing systems in burn-in tests. :) + */ +errcode_t ext2fs_sync_device(int fd, int flushb) +{ + /* + * We always sync the device in case we're running on old + * kernels for which we can lose data if we don't. (There + * still is a race condition for those kernels, but this + * reduces it greatly.) + */ +#if defined(HAVE_FSYNC) + if (fsync (fd) == -1) + return errno; +#endif + + if (flushb) { + errcode_t retval = 0; + +#ifdef BLKFLSBUF + if (ioctl (fd, BLKFLSBUF, 0) == 0) + return 0; + retval = errno; +#elif defined(__linux__) +#warning BLKFLSBUF not defined +#endif +#ifdef FDFLUSH + /* In case this is a floppy */ + if (ioctl(fd, FDFLUSH, 0) == 0) + return 0; + if (retval == 0) + retval = errno; +#elif defined(__linux__) +#warning FDFLUSH not defined +#endif + return retval; + } + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/freefs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/freefs.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,108 @@ +/* + * freefs.c --- free an ext2 filesystem + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" +#include "hashmap.h" + +void ext2fs_free(ext2_filsys fs) +{ + if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)) + return; + if (fs->image_io != fs->io) { + if (fs->image_io) + io_channel_close(fs->image_io); + } + if (fs->io) { + io_channel_close(fs->io); + } + if (fs->device_name) + ext2fs_free_mem(&fs->device_name); + if (fs->super) + ext2fs_free_mem(&fs->super); + if (fs->orig_super) + ext2fs_free_mem(&fs->orig_super); + if (fs->group_desc) + ext2fs_free_mem(&fs->group_desc); + if (fs->block_map) + ext2fs_free_block_bitmap(fs->block_map); + if (fs->inode_map) + ext2fs_free_inode_bitmap(fs->inode_map); + if (fs->image_header) + ext2fs_free_mem(&fs->image_header); + + if (fs->badblocks) + ext2fs_badblocks_list_free(fs->badblocks); + fs->badblocks = 0; + + if (fs->dblist) + ext2fs_free_dblist(fs->dblist); + + if (fs->icache) + ext2fs_free_inode_cache(fs->icache); + + if (fs->mmp_buf) + ext2fs_free_mem(&fs->mmp_buf); + if (fs->mmp_cmp) + ext2fs_free_mem(&fs->mmp_cmp); + + if (fs->block_sha_map) + ext2fs_hashmap_free(fs->block_sha_map); + + fs->magic = 0; + + ext2fs_zero_blocks2(NULL, 0, 0, NULL, NULL); + ext2fs_free_mem(&fs); +} + +/* + * This procedure frees a badblocks list. + */ +void ext2fs_u32_list_free(ext2_u32_list bb) +{ + if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST) + return; + + if (bb->list) + ext2fs_free_mem(&bb->list); + bb->list = 0; + ext2fs_free_mem(&bb); +} + +void ext2fs_badblocks_list_free(ext2_badblocks_list bb) +{ + ext2fs_u32_list_free((ext2_u32_list) bb); +} + + +/* + * Free a directory block list + */ +void ext2fs_free_dblist(ext2_dblist dblist) +{ + if (!dblist || (dblist->magic != EXT2_ET_MAGIC_DBLIST)) + return; + + if (dblist->list) + ext2fs_free_mem(&dblist->list); + dblist->list = 0; + if (dblist->fs && dblist->fs->dblist == dblist) + dblist->fs->dblist = 0; + dblist->magic = 0; + ext2fs_free_mem(&dblist); +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/gen_bitmap.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/gen_bitmap.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,607 @@ +/* + * gen_bitmap.c --- Generic (32-bit) bitmap routines + * + * Copyright (C) 2001 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" + +struct ext2fs_struct_generic_bitmap { + errcode_t magic; + ext2_filsys fs; + __u32 start, end; + __u32 real_end; + char * description; + char * bitmap; + errcode_t base_error_code; + __u32 reserved[7]; +}; + +#define EXT2FS_IS_32_BITMAP(bmap) \ + (((bmap)->magic == EXT2_ET_MAGIC_GENERIC_BITMAP) || \ + ((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP) || \ + ((bmap)->magic == EXT2_ET_MAGIC_INODE_BITMAP)) + +#define EXT2FS_IS_64_BITMAP(bmap) \ + (((bmap)->magic == EXT2_ET_MAGIC_GENERIC_BITMAP64) || \ + ((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP64) || \ + ((bmap)->magic == EXT2_ET_MAGIC_INODE_BITMAP64)) + +/* + * Used by previously inlined function, so we have to export this and + * not change the function signature + */ +void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap, + int code, unsigned long arg) +{ +#ifndef OMIT_COM_ERR + if (bitmap->description) + com_err(0, bitmap->base_error_code+code, + "#%lu for %s", arg, bitmap->description); + else + com_err(0, bitmap->base_error_code + code, "#%lu", arg); +#endif +} + +static errcode_t check_magic(ext2fs_generic_bitmap bitmap) +{ + if (!bitmap || !((bitmap->magic == EXT2_ET_MAGIC_GENERIC_BITMAP) || + (bitmap->magic == EXT2_ET_MAGIC_INODE_BITMAP) || + (bitmap->magic == EXT2_ET_MAGIC_BLOCK_BITMAP))) + return EXT2_ET_MAGIC_GENERIC_BITMAP; + return 0; +} + +errcode_t ext2fs_make_generic_bitmap(errcode_t magic, ext2_filsys fs, + __u32 start, __u32 end, __u32 real_end, + const char *descr, char *init_map, + ext2fs_generic_bitmap *ret) +{ + ext2fs_generic_bitmap bitmap; + errcode_t retval; + size_t size; + + retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap), + &bitmap); + if (retval) + return retval; + + bitmap->magic = magic; + bitmap->fs = fs; + bitmap->start = start; + bitmap->end = end; + bitmap->real_end = real_end; + switch (magic) { + case EXT2_ET_MAGIC_INODE_BITMAP: + bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK; + break; + case EXT2_ET_MAGIC_BLOCK_BITMAP: + bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK; + break; + default: + bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK; + } + if (descr) { + retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description); + if (retval) { + ext2fs_free_mem(&bitmap); + return retval; + } + strcpy(bitmap->description, descr); + } else + bitmap->description = 0; + + size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1); + /* Round up to allow for the BT x86 instruction */ + size = (size + 7) & ~3; + retval = ext2fs_get_mem(size, &bitmap->bitmap); + if (retval) { + ext2fs_free_mem(&bitmap->description); + ext2fs_free_mem(&bitmap); + return retval; + } + + if (init_map) + memcpy(bitmap->bitmap, init_map, size); + else + memset(bitmap->bitmap, 0, size); + *ret = bitmap; + return 0; +} + +errcode_t ext2fs_allocate_generic_bitmap(__u32 start, + __u32 end, + __u32 real_end, + const char *descr, + ext2fs_generic_bitmap *ret) +{ + return ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_GENERIC_BITMAP, 0, + start, end, real_end, descr, 0, ret); +} + +errcode_t ext2fs_copy_generic_bitmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap *dest) +{ + return (ext2fs_make_generic_bitmap(src->magic, src->fs, + src->start, src->end, + src->real_end, + src->description, src->bitmap, + dest)); +} + +void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap) +{ + if (check_magic(bitmap)) + return; + + bitmap->magic = 0; + if (bitmap->description) { + ext2fs_free_mem(&bitmap->description); + bitmap->description = 0; + } + if (bitmap->bitmap) { + ext2fs_free_mem(&bitmap->bitmap); + bitmap->bitmap = 0; + } + ext2fs_free_mem(&bitmap); +} + +int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap, + blk_t bitno) +{ + if (!EXT2FS_IS_32_BITMAP(bitmap)) { + if (EXT2FS_IS_64_BITMAP(bitmap)) { + ext2fs_warn_bitmap32(bitmap, __func__); + return ext2fs_test_generic_bmap(bitmap, bitno); + } +#ifndef OMIT_COM_ERR + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "test_bitmap(%lu)", (unsigned long) bitno); +#endif + return 0; + } + + if ((bitno < bitmap->start) || (bitno > bitmap->end)) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno); + return 0; + } + return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap); +} + +int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap, + __u32 bitno) +{ + if (!EXT2FS_IS_32_BITMAP(bitmap)) { + if (EXT2FS_IS_64_BITMAP(bitmap)) { + ext2fs_warn_bitmap32(bitmap, __func__); + return ext2fs_mark_generic_bmap(bitmap, bitno); + } +#ifndef OMIT_COM_ERR + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "mark_bitmap(%lu)", (unsigned long) bitno); +#endif + return 0; + } + + if ((bitno < bitmap->start) || (bitno > bitmap->end)) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_MARK_ERROR, bitno); + return 0; + } + return ext2fs_set_bit(bitno - bitmap->start, bitmap->bitmap); +} + +int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap, + blk_t bitno) +{ + if (!EXT2FS_IS_32_BITMAP(bitmap)) { + if (EXT2FS_IS_64_BITMAP(bitmap)) { + ext2fs_warn_bitmap32(bitmap, __func__); + return ext2fs_unmark_generic_bmap(bitmap, bitno); + } +#ifndef OMIT_COM_ERR + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "mark_bitmap(%lu)", (unsigned long) bitno); +#endif + return 0; + } + + if ((bitno < bitmap->start) || (bitno > bitmap->end)) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno); + return 0; + } + return ext2fs_clear_bit(bitno - bitmap->start, bitmap->bitmap); +} + +__u32 ext2fs_get_generic_bitmap_start(ext2fs_generic_bitmap bitmap) +{ + if (!EXT2FS_IS_32_BITMAP(bitmap)) { + if (EXT2FS_IS_64_BITMAP(bitmap)) { + ext2fs_warn_bitmap32(bitmap, __func__); + return ext2fs_get_generic_bmap_start(bitmap); + } +#ifndef OMIT_COM_ERR + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "get_bitmap_start"); +#endif + return 0; + } + + return bitmap->start; +} + +__u32 ext2fs_get_generic_bitmap_end(ext2fs_generic_bitmap bitmap) +{ + if (!EXT2FS_IS_32_BITMAP(bitmap)) { + if (EXT2FS_IS_64_BITMAP(bitmap)) { + ext2fs_warn_bitmap32(bitmap, __func__); + return ext2fs_get_generic_bmap_end(bitmap); + } +#ifndef OMIT_COM_ERR + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "get_bitmap_end"); +#endif + return 0; + } + return bitmap->end; +} + +void ext2fs_clear_generic_bitmap(ext2fs_generic_bitmap bitmap) +{ + if (!EXT2FS_IS_32_BITMAP(bitmap)) { + if (EXT2FS_IS_64_BITMAP(bitmap)) { + ext2fs_warn_bitmap32(bitmap, __func__); + ext2fs_clear_generic_bmap(bitmap); + return; + } +#ifndef OMIT_COM_ERR + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "clear_generic_bitmap"); +#endif + return; + } + + memset(bitmap->bitmap, 0, + (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1)); +} + +errcode_t ext2fs_fudge_generic_bitmap_end(ext2fs_inode_bitmap bitmap, + errcode_t magic, errcode_t neq, + ext2_ino_t end, ext2_ino_t *oend) +{ + EXT2_CHECK_MAGIC(bitmap, magic); + + if (end > bitmap->real_end) + return neq; + if (oend) + *oend = bitmap->end; + bitmap->end = end; + return 0; +} + +errcode_t ext2fs_resize_generic_bitmap(errcode_t magic, + __u32 new_end, __u32 new_real_end, + ext2fs_generic_bitmap bmap) +{ + errcode_t retval; + size_t size, new_size; + __u32 bitno; + + if (!bmap || (bmap->magic != magic)) + return magic; + + /* + * If we're expanding the bitmap, make sure all of the new + * parts of the bitmap are zero. + */ + if (new_end > bmap->end) { + bitno = bmap->real_end; + if (bitno > new_end) + bitno = new_end; + for (; bitno > bmap->end; bitno--) + ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap); + } + if (new_real_end == bmap->real_end) { + bmap->end = new_end; + return 0; + } + + size = ((bmap->real_end - bmap->start) / 8) + 1; + new_size = ((new_real_end - bmap->start) / 8) + 1; + + if (size != new_size) { + retval = ext2fs_resize_mem(size, new_size, &bmap->bitmap); + if (retval) + return retval; + } + if (new_size > size) + memset(bmap->bitmap + size, 0, new_size - size); + + bmap->end = new_end; + bmap->real_end = new_real_end; + return 0; +} + +errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq, + ext2fs_generic_bitmap bm1, + ext2fs_generic_bitmap bm2) +{ + blk_t i; + + if (!bm1 || bm1->magic != magic) + return magic; + if (!bm2 || bm2->magic != magic) + return magic; + + if ((bm1->start != bm2->start) || + (bm1->end != bm2->end) || + (memcmp(bm1->bitmap, bm2->bitmap, + (size_t) (bm1->end - bm1->start)/8))) + return neq; + + for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++) + if (ext2fs_fast_test_block_bitmap(bm1, i) != + ext2fs_fast_test_block_bitmap(bm2, i)) + return neq; + + return 0; +} + +void ext2fs_set_generic_bitmap_padding(ext2fs_generic_bitmap map) +{ + __u32 i, j; + + /* Protect loop from wrap-around if map->real_end is maxed */ + for (i=map->end+1, j = i - map->start; + i <= map->real_end && i > map->end; + i++, j++) + ext2fs_set_bit(j, map->bitmap); +} + +errcode_t ext2fs_get_generic_bitmap_range(ext2fs_generic_bitmap bmap, + errcode_t magic, + __u32 start, __u32 num, + void *out) +{ + if (!bmap || (bmap->magic != magic)) + return magic; + + if ((start < bmap->start) || (start+num-1 > bmap->real_end)) + return EXT2_ET_INVALID_ARGUMENT; + + memcpy(out, bmap->bitmap + (start >> 3), (num+7) >> 3); + return 0; +} + +errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap bmap, + errcode_t magic, + __u32 start, __u32 num, + void *in) +{ + if (!bmap || (bmap->magic != magic)) + return magic; + + if ((start < bmap->start) || (start+num-1 > bmap->real_end)) + return EXT2_ET_INVALID_ARGUMENT; + + memcpy(bmap->bitmap + (start >> 3), in, (num+7) >> 3); + return 0; +} + +/* + * Compare @mem to zero buffer by 256 bytes. + * Return 1 if @mem is zeroed memory, otherwise return 0. + */ +int ext2fs_mem_is_zero(const char *mem, size_t len) +{ + static const char zero_buf[256]; + + while (len >= sizeof(zero_buf)) { + if (memcmp(mem, zero_buf, sizeof(zero_buf))) + return 0; + len -= sizeof(zero_buf); + mem += sizeof(zero_buf); + } + /* Deal with leftover bytes. */ + if (len) + return !memcmp(mem, zero_buf, len); + return 1; +} + +/* + * Return true if all of the bits in a specified range are clear + */ +static int ext2fs_test_clear_generic_bitmap_range(ext2fs_generic_bitmap bitmap, + unsigned int start, + unsigned int len) +{ + size_t start_byte, len_byte = len >> 3; + unsigned int start_bit, len_bit = len % 8; + int first_bit = 0; + int last_bit = 0; + int mark_count = 0; + int mark_bit = 0; + int i; + const char *ADDR = bitmap->bitmap; + + start -= bitmap->start; + start_byte = start >> 3; + start_bit = start % 8; + + if (start_bit != 0) { + /* + * The compared start block number or start inode number + * is not the first bit in a byte. + */ + mark_count = 8 - start_bit; + if (len < 8 - start_bit) { + mark_count = (int)len; + mark_bit = len + start_bit - 1; + } else + mark_bit = 7; + + for (i = mark_count; i > 0; i--, mark_bit--) + first_bit |= 1 << mark_bit; + + /* + * Compare blocks or inodes in the first byte. + * If there is any marked bit, this function returns 0. + */ + if (first_bit & ADDR[start_byte]) + return 0; + else if (len <= 8 - start_bit) + return 1; + + start_byte++; + len_bit = (len - mark_count) % 8; + len_byte = (len - mark_count) >> 3; + } + + /* + * The compared start block number or start inode number is + * the first bit in a byte. + */ + if (len_bit != 0) { + /* + * The compared end block number or end inode number is + * not the last bit in a byte. + */ + for (mark_bit = len_bit - 1; mark_bit >= 0; mark_bit--) + last_bit |= 1 << mark_bit; + + /* + * Compare blocks or inodes in the last byte. + * If there is any marked bit, this function returns 0. + */ + if (last_bit & ADDR[start_byte + len_byte]) + return 0; + else if (len_byte == 0) + return 1; + } + + /* Check whether all bytes are 0 */ + return ext2fs_mem_is_zero(ADDR + start_byte, len_byte); +} + +errcode_t ext2fs_find_first_zero_generic_bitmap(ext2fs_generic_bitmap bitmap, + __u32 start, __u32 end, + __u32 *out) +{ + blk_t b; + + if (start < bitmap->start || end > bitmap->end || start > end) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start); + return EINVAL; + } + + while (start <= end) { + b = ext2fs_test_bit(start - bitmap->start, bitmap->bitmap); + if (!b) { + *out = start; + return 0; + } + start++; + } + + return ENOENT; +} + +errcode_t ext2fs_find_first_set_generic_bitmap(ext2fs_generic_bitmap bitmap, + __u32 start, __u32 end, + __u32 *out) +{ + blk_t b; + + if (start < bitmap->start || end > bitmap->end || start > end) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start); + return EINVAL; + } + + while (start <= end) { + b = ext2fs_test_bit(start - bitmap->start, bitmap->bitmap); + if (b) { + *out = start; + return 0; + } + start++; + } + + return ENOENT; +} + +int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num) +{ + EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_BLOCK_BITMAP); + if ((block < bitmap->start) || (block+num-1 > bitmap->real_end)) { + ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST, + block, bitmap->description); + return 0; + } + return ext2fs_test_clear_generic_bitmap_range((ext2fs_generic_bitmap) + bitmap, block, num); +} + +int ext2fs_test_inode_bitmap_range(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode, int num) +{ + EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP); + if ((inode < bitmap->start) || (inode+num-1 > bitmap->real_end)) { + ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_TEST, + inode, bitmap->description); + return 0; + } + return ext2fs_test_clear_generic_bitmap_range((ext2fs_generic_bitmap) + bitmap, inode, num); +} + +void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num) +{ + int i; + + if ((block < bitmap->start) || (block+num-1 > bitmap->end)) { + ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block, + bitmap->description); + return; + } + for (i=0; i < num; i++) + ext2fs_fast_set_bit(block + i - bitmap->start, bitmap->bitmap); +} + +void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num) +{ + int i; + + if ((block < bitmap->start) || (block+num-1 > bitmap->end)) { + ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block, + bitmap->description); + return; + } + for (i=0; i < num; i++) + ext2fs_fast_clear_bit(block + i - bitmap->start, + bitmap->bitmap); +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/gen_bitmap64.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/gen_bitmap64.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,907 @@ +/* + * gen_bitmap64.c --- routines to read, write, and manipulate the new qinode and + * block bitmaps. + * + * Copyright (C) 2007, 2008 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" +#include "bmap64.h" + +/* + * Design of 64-bit bitmaps + * + * In order maintain ABI compatibility with programs that don't + * understand about 64-bit blocks/inodes, + * ext2fs_allocate_inode_bitmap() and ext2fs_allocate_block_bitmap() + * will create old-style bitmaps unless the application passes the + * flag EXT2_FLAG_64BITS to ext2fs_open(). If this flag is + * passed, then we know the application has been recompiled, so we can + * use the new-style bitmaps. If it is not passed, we have to return + * an error if trying to open a filesystem which needs 64-bit bitmaps. + * + * The new bitmaps use a new set of structure magic numbers, so that + * both the old-style and new-style interfaces can identify which + * version of the data structure was used. Both the old-style and + * new-style interfaces will support either type of bitmap, although + * of course 64-bit operation will only be possible when both the + * new-style interface and the new-style bitmap are used. + * + * For example, the new bitmap interfaces will check the structure + * magic numbers and so will be able to detect old-stype bitmap. If + * they see an old-style bitmap, they will pass it to the gen_bitmap.c + * functions for handling. The same will be true for the old + * interfaces as well. + * + * The new-style interfaces will have several different back-end + * implementations, so we can support different encodings that are + * appropriate for different applications. In general the default + * should be whatever makes sense, and what the application/library + * will use. However, e2fsck may need specialized implementations for + * its own uses. For example, when doing parent directory pointer + * loop detections in pass 3, the bitmap will *always* be sparse, so + * e2fsck can request an encoding which is optimized for that. + */ + +static void warn_bitmap(ext2fs_generic_bitmap bitmap, + int code, __u64 arg) +{ +#ifndef OMIT_COM_ERR + if (bitmap->description) + com_err(0, bitmap->base_error_code+code, + "#%llu for %s", arg, bitmap->description); + else + com_err(0, bitmap->base_error_code + code, "#%llu", arg); +#endif +} + +#ifdef ENABLE_BMAP_STATS_OPS +#define INC_STAT(map, name) map->stats.name +#else +#define INC_STAT(map, name) ;; +#endif + + +errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic, + int type, __u64 start, __u64 end, + __u64 real_end, + const char *descr, + ext2fs_generic_bitmap *ret) +{ + ext2fs_generic_bitmap bitmap; + struct ext2_bitmap_ops *ops; + ext2_ino_t num_dirs; + errcode_t retval; + + if (!type) + type = EXT2FS_BMAP64_BITARRAY; + + switch (type) { + case EXT2FS_BMAP64_BITARRAY: + ops = &ext2fs_blkmap64_bitarray; + break; + case EXT2FS_BMAP64_RBTREE: + ops = &ext2fs_blkmap64_rbtree; + break; + case EXT2FS_BMAP64_AUTODIR: + retval = ext2fs_get_num_dirs(fs, &num_dirs); + if (retval || num_dirs > (fs->super->s_inodes_count / 320)) + ops = &ext2fs_blkmap64_bitarray; + else + ops = &ext2fs_blkmap64_rbtree; + break; + default: + return EINVAL; + } + + retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap), + &bitmap); + if (retval) + return retval; + +#ifdef ENABLE_BMAP_STATS + if (gettimeofday(&bitmap->stats.created, + (struct timezone *) NULL) == -1) { + perror("gettimeofday"); + ext2fs_free_mem(&bitmap); + return 1; + } + bitmap->stats.type = type; +#endif + + /* XXX factor out, repeated in copy_bmap */ + bitmap->magic = magic; + bitmap->fs = fs; + bitmap->start = start; + bitmap->end = end; + bitmap->real_end = real_end; + bitmap->bitmap_ops = ops; + bitmap->cluster_bits = 0; + switch (magic) { + case EXT2_ET_MAGIC_INODE_BITMAP64: + bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK; + break; + case EXT2_ET_MAGIC_BLOCK_BITMAP64: + bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK; + bitmap->cluster_bits = fs->cluster_ratio_bits; + break; + default: + bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK; + } + if (descr) { + retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description); + if (retval) { + ext2fs_free_mem(&bitmap); + return retval; + } + strcpy(bitmap->description, descr); + } else + bitmap->description = 0; + + retval = bitmap->bitmap_ops->new_bmap(fs, bitmap); + if (retval) { + ext2fs_free_mem(&bitmap->description); + ext2fs_free_mem(&bitmap); + return retval; + } + + *ret = bitmap; + return 0; +} + +#ifdef ENABLE_BMAP_STATS +static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap bitmap) +{ + struct ext2_bmap_statistics *stats = &bitmap->stats; +#ifdef ENABLE_BMAP_STATS_OPS + float mark_seq_perc = 0.0, test_seq_perc = 0.0; + float mark_back_perc = 0.0, test_back_perc = 0.0; +#endif + double inuse; + struct timeval now; + +#ifdef ENABLE_BMAP_STATS_OPS + if (stats->test_count) { + test_seq_perc = ((float)stats->test_seq / + stats->test_count) * 100; + test_back_perc = ((float)stats->test_back / + stats->test_count) * 100; + } + + if (stats->mark_count) { + mark_seq_perc = ((float)stats->mark_seq / + stats->mark_count) * 100; + mark_back_perc = ((float)stats->mark_back / + stats->mark_count) * 100; + } +#endif + + if (gettimeofday(&now, (struct timezone *) NULL) == -1) { + perror("gettimeofday"); + return; + } + + inuse = (double) now.tv_sec + \ + (((double) now.tv_usec) * 0.000001); + inuse -= (double) stats->created.tv_sec + \ + (((double) stats->created.tv_usec) * 0.000001); + + fprintf(stderr, "\n[+] %s bitmap (type %d)\n", bitmap->description, + stats->type); + fprintf(stderr, "=================================================\n"); +#ifdef ENABLE_BMAP_STATS_OPS + fprintf(stderr, "%16llu bits long\n", + bitmap->real_end - bitmap->start); + fprintf(stderr, "%16lu copy_bmap\n%16lu resize_bmap\n", + stats->copy_count, stats->resize_count); + fprintf(stderr, "%16lu mark bmap\n%16lu unmark_bmap\n", + stats->mark_count, stats->unmark_count); + fprintf(stderr, "%16lu test_bmap\n%16lu mark_bmap_extent\n", + stats->test_count, stats->mark_ext_count); + fprintf(stderr, "%16lu unmark_bmap_extent\n" + "%16lu test_clear_bmap_extent\n", + stats->unmark_ext_count, stats->test_ext_count); + fprintf(stderr, "%16lu set_bmap_range\n%16lu set_bmap_range\n", + stats->set_range_count, stats->get_range_count); + fprintf(stderr, "%16lu clear_bmap\n%16lu contiguous bit test (%.2f%%)\n", + stats->clear_count, stats->test_seq, test_seq_perc); + fprintf(stderr, "%16lu contiguous bit mark (%.2f%%)\n" + "%16llu bits tested backwards (%.2f%%)\n", + stats->mark_seq, mark_seq_perc, + stats->test_back, test_back_perc); + fprintf(stderr, "%16llu bits marked backwards (%.2f%%)\n" + "%16.2f seconds in use\n", + stats->mark_back, mark_back_perc, inuse); +#endif /* ENABLE_BMAP_STATS_OPS */ +} +#endif + +void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap) +{ + if (!bmap) + return; + + if (EXT2FS_IS_32_BITMAP(bmap)) { + ext2fs_free_generic_bitmap(bmap); + return; + } + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return; + +#ifdef ENABLE_BMAP_STATS + if (getenv("E2FSPROGS_BITMAP_STATS")) { + ext2fs_print_bmap_statistics(bmap); + bmap->bitmap_ops->print_stats(bmap); + } +#endif + + bmap->bitmap_ops->free_bmap(bmap); + + if (bmap->description) { + ext2fs_free_mem(&bmap->description); + bmap->description = 0; + } + bmap->magic = 0; + ext2fs_free_mem(&bmap); +} + +errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap *dest) +{ + char *descr, *new_descr; + ext2fs_generic_bitmap new_bmap; + errcode_t retval; + + if (!src) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(src)) + return ext2fs_copy_generic_bitmap(src, dest); + + if (!EXT2FS_IS_64_BITMAP(src)) + return EINVAL; + + /* Allocate a new bitmap struct */ + retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap), + &new_bmap); + if (retval) + return retval; + + +#ifdef ENABLE_BMAP_STATS_OPS + src->stats.copy_count++; +#endif +#ifdef ENABLE_BMAP_STATS + if (gettimeofday(&new_bmap->stats.created, + (struct timezone *) NULL) == -1) { + perror("gettimeofday"); + ext2fs_free_mem(&new_bmap); + return 1; + } + new_bmap->stats.type = src->stats.type; +#endif + + /* Copy all the high-level parts over */ + new_bmap->magic = src->magic; + new_bmap->fs = src->fs; + new_bmap->start = src->start; + new_bmap->end = src->end; + new_bmap->real_end = src->real_end; + new_bmap->bitmap_ops = src->bitmap_ops; + new_bmap->base_error_code = src->base_error_code; + new_bmap->cluster_bits = src->cluster_bits; + + descr = src->description; + if (descr) { + retval = ext2fs_get_mem(strlen(descr)+10, &new_descr); + if (retval) { + ext2fs_free_mem(&new_bmap); + return retval; + } + strcpy(new_descr, "copy of "); + strcat(new_descr, descr); + new_bmap->description = new_descr; + } + + retval = src->bitmap_ops->copy_bmap(src, new_bmap); + if (retval) { + ext2fs_free_mem(&new_bmap->description); + ext2fs_free_mem(&new_bmap); + return retval; + } + + *dest = new_bmap; + + return 0; +} + +errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap, + __u64 new_end, + __u64 new_real_end) +{ + if (!bmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bmap)) + return ext2fs_resize_generic_bitmap(bmap->magic, new_end, + new_real_end, bmap); + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return EINVAL; + + INC_STAT(bmap, resize_count); + + return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end); +} + +errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap, + errcode_t neq, + __u64 end, __u64 *oend) +{ + if (!bitmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bitmap)) { + ext2_ino_t tmp_oend; + int retval; + + retval = ext2fs_fudge_generic_bitmap_end(bitmap, bitmap->magic, + neq, end, &tmp_oend); + if (oend) + *oend = tmp_oend; + return retval; + } + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return EINVAL; + + if (end > bitmap->real_end) + return neq; + if (oend) + *oend = bitmap->end; + bitmap->end = end; + return 0; +} + +__u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap bitmap) +{ + if (!bitmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bitmap)) + return ext2fs_get_generic_bitmap_start(bitmap); + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return EINVAL; + + return bitmap->start; +} + +__u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap bitmap) +{ + if (!bitmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bitmap)) + return ext2fs_get_generic_bitmap_end(bitmap); + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return EINVAL; + + return bitmap->end; +} + +void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap) +{ + if (EXT2FS_IS_32_BITMAP(bitmap)) + ext2fs_clear_generic_bitmap(bitmap); + else + bitmap->bitmap_ops->clear_bmap (bitmap); +} + +int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 arg) +{ + if (!bitmap) + return 0; + + if (EXT2FS_IS_32_BITMAP(bitmap)) { + if (arg & ~0xffffffffULL) { + ext2fs_warn_bitmap2(bitmap, + EXT2FS_MARK_ERROR, 0xffffffff); + return 0; + } + return ext2fs_mark_generic_bitmap(bitmap, arg); + } + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return 0; + + arg >>= bitmap->cluster_bits; + +#ifdef ENABLE_BMAP_STATS_OPS + if (arg == bitmap->stats.last_marked + 1) + bitmap->stats.mark_seq++; + if (arg < bitmap->stats.last_marked) + bitmap->stats.mark_back++; + bitmap->stats.last_marked = arg; + bitmap->stats.mark_count++; +#endif + + if ((arg < bitmap->start) || (arg > bitmap->end)) { + warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg); + return 0; + } + + return bitmap->bitmap_ops->mark_bmap(bitmap, arg); +} + +int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 arg) +{ + if (!bitmap) + return 0; + + if (EXT2FS_IS_32_BITMAP(bitmap)) { + if (arg & ~0xffffffffULL) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, + 0xffffffff); + return 0; + } + return ext2fs_unmark_generic_bitmap(bitmap, arg); + } + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return 0; + + arg >>= bitmap->cluster_bits; + + INC_STAT(bitmap, unmark_count); + + if ((arg < bitmap->start) || (arg > bitmap->end)) { + warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg); + return 0; + } + + return bitmap->bitmap_ops->unmark_bmap(bitmap, arg); +} + +int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 arg) +{ + if (!bitmap) + return 0; + + if (EXT2FS_IS_32_BITMAP(bitmap)) { + if (arg & ~0xffffffffULL) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, + 0xffffffff); + return 0; + } + return ext2fs_test_generic_bitmap(bitmap, arg); + } + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return 0; + + arg >>= bitmap->cluster_bits; + +#ifdef ENABLE_BMAP_STATS_OPS + bitmap->stats.test_count++; + if (arg == bitmap->stats.last_tested + 1) + bitmap->stats.test_seq++; + if (arg < bitmap->stats.last_tested) + bitmap->stats.test_back++; + bitmap->stats.last_tested = arg; +#endif + + if ((arg < bitmap->start) || (arg > bitmap->end)) { + warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg); + return 0; + } + + return bitmap->bitmap_ops->test_bmap(bitmap, arg); +} + +errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap, + __u64 start, unsigned int num, + void *in) +{ + if (!bmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bmap)) { + if ((start+num-1) & ~0xffffffffULL) { + ext2fs_warn_bitmap2(bmap, EXT2FS_UNMARK_ERROR, + 0xffffffff); + return EINVAL; + } + return ext2fs_set_generic_bitmap_range(bmap, bmap->magic, + start, num, in); + } + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return EINVAL; + + INC_STAT(bmap, set_range_count); + + return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in); +} + +errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap, + __u64 start, unsigned int num, + void *out) +{ + if (!bmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bmap)) { + if ((start+num-1) & ~0xffffffffULL) { + ext2fs_warn_bitmap2(bmap, + EXT2FS_UNMARK_ERROR, 0xffffffff); + return EINVAL; + } + return ext2fs_get_generic_bitmap_range(bmap, bmap->magic, + start, num, out); + } + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return EINVAL; + + INC_STAT(bmap, get_range_count); + + return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out); +} + +errcode_t ext2fs_compare_generic_bmap(errcode_t neq, + ext2fs_generic_bitmap bm1, + ext2fs_generic_bitmap bm2) +{ + blk64_t i; + + if (!bm1 || !bm2) + return EINVAL; + if (bm1->magic != bm2->magic) + return EINVAL; + + /* Now we know both bitmaps have the same magic */ + if (EXT2FS_IS_32_BITMAP(bm1)) + return ext2fs_compare_generic_bitmap(bm1->magic, neq, bm1, bm2); + + if (!EXT2FS_IS_64_BITMAP(bm1)) + return EINVAL; + + if ((bm1->start != bm2->start) || + (bm1->end != bm2->end)) + return neq; + + for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++) + if (ext2fs_test_generic_bmap(bm1, i) != + ext2fs_test_generic_bmap(bm2, i)) + return neq; + + return 0; +} + +void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap) +{ + __u64 start, num; + + if (EXT2FS_IS_32_BITMAP(bmap)) { + ext2fs_set_generic_bitmap_padding(bmap); + return; + } + + start = bmap->end + 1; + num = bmap->real_end - bmap->end; + bmap->bitmap_ops->mark_bmap_extent(bmap, start, num); + /* XXX ought to warn on error */ +} + +int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bmap, + blk64_t block, unsigned int num) +{ + __u64 end = block + num; + + if (!bmap) + return EINVAL; + + if (num == 1) + return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap) + bmap, block); + + if (EXT2FS_IS_32_BITMAP(bmap)) { + if ((block+num-1) & ~0xffffffffULL) { + ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, + EXT2FS_UNMARK_ERROR, 0xffffffff); + return EINVAL; + } + return ext2fs_test_block_bitmap_range( + (ext2fs_generic_bitmap) bmap, block, num); + } + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return EINVAL; + + INC_STAT(bmap, test_ext_count); + + /* convert to clusters if necessary */ + block >>= bmap->cluster_bits; + end += (1 << bmap->cluster_bits) - 1; + end >>= bmap->cluster_bits; + num = end - block; + + if ((block < bmap->start) || (block+num-1 > bmap->end)) { + ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST, block, + bmap->description); + return EINVAL; + } + + return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num); +} + +void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap, + blk64_t block, unsigned int num) +{ + __u64 end = block + num; + + if (!bmap) + return; + + if (EXT2FS_IS_32_BITMAP(bmap)) { + if ((block+num-1) & ~0xffffffffULL) { + ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, + EXT2FS_UNMARK_ERROR, 0xffffffff); + return; + } + ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap, + block, num); + } + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return; + + INC_STAT(bmap, mark_ext_count); + + /* convert to clusters if necessary */ + block >>= bmap->cluster_bits; + end += (1 << bmap->cluster_bits) - 1; + end >>= bmap->cluster_bits; + num = end - block; + + if ((block < bmap->start) || (block+num-1 > bmap->end)) { + ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block, + bmap->description); + return; + } + + bmap->bitmap_ops->mark_bmap_extent(bmap, block, num); +} + +void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bmap, + blk64_t block, unsigned int num) +{ + __u64 end = block + num; + + if (!bmap) + return; + + if (EXT2FS_IS_32_BITMAP(bmap)) { + if ((block+num-1) & ~0xffffffffULL) { + ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, + EXT2FS_UNMARK_ERROR, 0xffffffff); + return; + } + ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap, + block, num); + } + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return; + + INC_STAT(bmap, unmark_ext_count); + + /* convert to clusters if necessary */ + block >>= bmap->cluster_bits; + end += (1 << bmap->cluster_bits) - 1; + end >>= bmap->cluster_bits; + num = end - block; + + if ((block < bmap->start) || (block+num-1 > bmap->end)) { + ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block, + bmap->description); + return; + } + + bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num); +} + +void ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap, const char *func) +{ +#ifndef OMIT_COM_ERR + if (bitmap && bitmap->description) + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "called %s with 64-bit bitmap for %s", func, + bitmap->description); + else + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "called %s with 64-bit bitmap", func); +#endif +} + +errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, + ext2fs_block_bitmap *bitmap) +{ + ext2fs_block_bitmap cmap, bmap; + errcode_t retval; + blk64_t i, b_end, c_end; + int n, ratio; + + bmap = *bitmap; + + if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(bmap)) + return 0; /* Nothing to do */ + + retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap", + &cmap); + if (retval) + return retval; + + i = bmap->start; + b_end = bmap->end; + bmap->end = bmap->real_end; + c_end = cmap->end; + cmap->end = cmap->real_end; + n = 0; + ratio = 1 << fs->cluster_ratio_bits; + while (i < bmap->real_end) { + if (ext2fs_test_block_bitmap2(bmap, i)) { + ext2fs_mark_block_bitmap2(cmap, i); + i += ratio - n; + n = 0; + continue; + } + i++; n++; + if (n >= ratio) + n = 0; + } + bmap->end = b_end; + cmap->end = c_end; + ext2fs_free_block_bitmap(bmap); + *bitmap = cmap; + return 0; +} + +errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out) +{ + __u64 cstart, cend, cout; + errcode_t retval; + + if (!bitmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bitmap)) { + blk_t blk = 0; + + if (((start) & ~0xffffffffULL) || + ((end) & ~0xffffffffULL)) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start); + return EINVAL; + } + + retval = ext2fs_find_first_zero_generic_bitmap(bitmap, start, + end, &blk); + if (retval == 0) + *out = blk; + return retval; + } + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return EINVAL; + + cstart = start >> bitmap->cluster_bits; + cend = end >> bitmap->cluster_bits; + + if (cstart < bitmap->start || cend > bitmap->end || start > end) { + warn_bitmap(bitmap, EXT2FS_TEST_ERROR, start); + return EINVAL; + } + + if (bitmap->bitmap_ops->find_first_zero) { + retval = bitmap->bitmap_ops->find_first_zero(bitmap, cstart, + cend, &cout); + if (retval) + return retval; + found: + cout <<= bitmap->cluster_bits; + *out = (cout >= start) ? cout : start; + return 0; + } + + for (cout = cstart; cout <= cend; cout++) + if (!bitmap->bitmap_ops->test_bmap(bitmap, cout)) + goto found; + + return ENOENT; +} + +errcode_t ext2fs_find_first_set_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out) +{ + __u64 cstart, cend, cout; + errcode_t retval; + + if (!bitmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bitmap)) { + blk_t blk = 0; + + if (((start) & ~0xffffffffULL) || + ((end) & ~0xffffffffULL)) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start); + return EINVAL; + } + + retval = ext2fs_find_first_set_generic_bitmap(bitmap, start, + end, &blk); + if (retval == 0) + *out = blk; + return retval; + } + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return EINVAL; + + cstart = start >> bitmap->cluster_bits; + cend = end >> bitmap->cluster_bits; + + if (cstart < bitmap->start || cend > bitmap->end || start > end) { + warn_bitmap(bitmap, EXT2FS_TEST_ERROR, start); + return EINVAL; + } + + if (bitmap->bitmap_ops->find_first_set) { + retval = bitmap->bitmap_ops->find_first_set(bitmap, cstart, + cend, &cout); + if (retval) + return retval; + found: + cout <<= bitmap->cluster_bits; + *out = (cout >= start) ? cout : start; + return 0; + } + + for (cout = cstart; cout <= cend; cout++) + if (bitmap->bitmap_ops->test_bmap(bitmap, cout)) + goto found; + + return ENOENT; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/gen_crc32ctable.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/gen_crc32ctable.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,117 @@ +#include +#include "crc32c_defs.h" +#include + +#define ENTRIES_PER_LINE 4 + +#if CRC_LE_BITS > 8 +# define LE_TABLE_ROWS (CRC_LE_BITS/8) +# define LE_TABLE_SIZE 256 +#else +# define LE_TABLE_ROWS 1 +# define LE_TABLE_SIZE (1 << CRC_LE_BITS) +#endif + +#if CRC_BE_BITS > 8 +# define BE_TABLE_ROWS (CRC_BE_BITS/8) +# define BE_TABLE_SIZE 256 +#else +# define BE_TABLE_ROWS 1 +# define BE_TABLE_SIZE (1 << CRC_BE_BITS) +#endif + +static uint32_t crc32table_be[BE_TABLE_ROWS][256]; +static uint32_t crc32ctable_le[LE_TABLE_ROWS][256]; + +/** + * crc32init_le() - allocate and initialize LE table data + * + * crc is the crc of the byte i; other entries are filled in based on the + * fact that crctable[i^j] = crctable[i] ^ crctable[j]. + * + */ +static void crc32cinit_le(void) +{ + unsigned i, j; + uint32_t crc = 1; + + crc32ctable_le[0][0] = 0; + + for (i = LE_TABLE_SIZE >> 1; i; i >>= 1) { + crc = (crc >> 1) ^ ((crc & 1) ? CRC32C_POLY_LE : 0); + for (j = 0; j < LE_TABLE_SIZE; j += 2 * i) + crc32ctable_le[0][i + j] = crc ^ crc32ctable_le[0][j]; + } + for (i = 0; i < LE_TABLE_SIZE; i++) { + crc = crc32ctable_le[0][i]; + for (j = 1; j < LE_TABLE_ROWS; j++) { + crc = crc32ctable_le[0][crc & 0xff] ^ (crc >> 8); + crc32ctable_le[j][i] = crc; + } + } +} + +/** + * crc32init_be() - allocate and initialize BE table data + */ +static void crc32init_be(void) +{ + unsigned i, j; + uint32_t crc = 0x80000000; + + crc32table_be[0][0] = 0; + + for (i = 1; i < BE_TABLE_SIZE; i <<= 1) { + crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0); + for (j = 0; j < i; j++) + crc32table_be[0][i + j] = crc ^ crc32table_be[0][j]; + } + for (i = 0; i < BE_TABLE_SIZE; i++) { + crc = crc32table_be[0][i]; + for (j = 1; j < BE_TABLE_ROWS; j++) { + crc = crc32table_be[0][(crc >> 24) & 0xff] ^ (crc << 8); + crc32table_be[j][i] = crc; + } + } +} + +static void output_table(uint32_t (*table)[256], int rows, int len, char *trans) +{ + int i, j; + + for (j = 0 ; j < rows; j++) { + printf("{"); + for (i = 0; i < len - 1; i++) { + if (i % ENTRIES_PER_LINE == 0) + printf("\n"); + printf("%s(0x%8.8xL), ", trans, table[j][i]); + } + printf("%s(0x%8.8xL)},\n", trans, table[j][len - 1]); + } +} + +int main(int argc, char **argv) +{ + printf("/* this file is generated - do not edit */\n\n"); + + if (CRC_BE_BITS > 1) { + crc32init_be(); + printf("static const uint32_t " + "crc32table_be[%d][%d] = {", + BE_TABLE_ROWS, BE_TABLE_SIZE); + output_table(crc32table_be, LE_TABLE_ROWS, + BE_TABLE_SIZE, "tobe"); + printf("};\n"); + } + if (CRC_LE_BITS > 1) { + crc32cinit_le(); + printf("static const uint32_t " + "crc32ctable_le[%d][%d] = {", + LE_TABLE_ROWS, LE_TABLE_SIZE); + output_table(crc32ctable_le, LE_TABLE_ROWS, + LE_TABLE_SIZE, "tole"); + printf("};\n"); + } + + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/get_num_dirs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/get_num_dirs.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,50 @@ +/* + * get_num_dirs.c -- calculate number of directories + * + * Copyright 1997 by Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "ext2_fs.h" +#include "ext2fsP.h" + +/* + * Returns the number of directories in the filesystem as reported by + * the group descriptors. Of course, the group descriptors could be + * wrong! + */ +errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs) +{ + dgrp_t i; + ext2_ino_t num_dirs, max_dirs; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + num_dirs = 0; + max_dirs = fs->super->s_inodes_per_group; + for (i = 0; i < fs->group_desc_count; i++) { + if (ext2fs_bg_used_dirs_count(fs, i) > max_dirs) + num_dirs += max_dirs / 8; + else + num_dirs += ext2fs_bg_used_dirs_count(fs, i); + } + if (num_dirs > fs->super->s_inodes_count) + num_dirs = fs->super->s_inodes_count; + + *ret_num_dirs = num_dirs; + + return 0; +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/get_pathname.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/get_pathname.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,171 @@ +/* + * get_pathname.c --- do directory/inode -> name translation + * + * Copyright (C) 1993, 1994, 1995 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +/* + * + * ext2fs_get_pathname(fs, dir, ino, name) + * + * This function translates takes two inode numbers into a + * string, placing the result in . is the containing + * directory inode, and is the inode number itself. If + * is zero, then ext2fs_get_pathname will return pathname + * of the the directory . + * + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +struct get_pathname_struct { + ext2_ino_t search_ino; + ext2_ino_t parent; + char *name; + errcode_t errcode; +}; + +#ifdef __TURBOC__ + #pragma argsused +#endif +static int get_pathname_proc(struct ext2_dir_entry *dirent, + int offset EXT2FS_ATTR((unused)), + int blocksize EXT2FS_ATTR((unused)), + char *buf EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct get_pathname_struct *gp; + errcode_t retval; + int name_len = ext2fs_dirent_name_len(dirent); + + gp = (struct get_pathname_struct *) priv_data; + + if ((name_len == 2) && !strncmp(dirent->name, "..", 2)) + gp->parent = dirent->inode; + if (dirent->inode == gp->search_ino) { + retval = ext2fs_get_mem(name_len + 1, &gp->name); + if (retval) { + gp->errcode = retval; + return DIRENT_ABORT; + } + strncpy(gp->name, dirent->name, name_len); + gp->name[name_len] = '\0'; + return DIRENT_ABORT; + } + return 0; +} + +static errcode_t ext2fs_get_pathname_int(ext2_filsys fs, ext2_ino_t dir, + ext2_ino_t ino, int maxdepth, + char *buf, char **name) +{ + struct get_pathname_struct gp; + char *parent_name = 0, *ret; + errcode_t retval; + + if (dir == ino) { + retval = ext2fs_get_mem(2, name); + if (retval) + return retval; + strcpy(*name, (dir == EXT2_ROOT_INO) ? "/" : "."); + return 0; + } + + if (!dir || (maxdepth < 0)) { + retval = ext2fs_get_mem(4, name); + if (retval) + return retval; + strcpy(*name, "..."); + return 0; + } + + gp.search_ino = ino; + gp.parent = 0; + gp.name = 0; + gp.errcode = 0; + + retval = ext2fs_dir_iterate(fs, dir, 0, buf, get_pathname_proc, &gp); + if (retval == EXT2_ET_NO_DIRECTORY) { + char tmp[32]; + + if (ino) + snprintf(tmp, sizeof(tmp), "<%u>/<%u>", dir, ino); + else + snprintf(tmp, sizeof(tmp), "<%u>", dir); + retval = ext2fs_get_mem(strlen(tmp)+1, name); + if (retval) + goto cleanup; + strcpy(*name, tmp); + return 0; + } else if (retval) + goto cleanup; + if (gp.errcode) { + retval = gp.errcode; + goto cleanup; + } + + retval = ext2fs_get_pathname_int(fs, gp.parent, dir, maxdepth-1, + buf, &parent_name); + if (retval) + goto cleanup; + if (!ino) { + *name = parent_name; + return 0; + } + + if (gp.name) + retval = ext2fs_get_mem(strlen(parent_name)+strlen(gp.name)+2, + &ret); + else + retval = ext2fs_get_mem(strlen(parent_name)+5, &ret); + if (retval) + goto cleanup; + + ret[0] = 0; + if (parent_name[1]) + strcat(ret, parent_name); + strcat(ret, "/"); + if (gp.name) + strcat(ret, gp.name); + else + strcat(ret, "???"); + *name = ret; + retval = 0; + +cleanup: + ext2fs_free_mem(&parent_name); + ext2fs_free_mem(&gp.name); + return retval; +} + +errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino, + char **name) +{ + char *buf; + errcode_t retval; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + retval = ext2fs_get_mem(fs->blocksize, &buf); + if (retval) + return retval; + if (dir == ino) + ino = 0; + retval = ext2fs_get_pathname_int(fs, dir, ino, 32, buf, name); + ext2fs_free_mem(&buf); + return retval; + +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/getsectsize.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/getsectsize.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,136 @@ +/* + * getsectsize.c --- get the sector size of a device. + * + * Copyright (C) 1995, 1995 Theodore Ts'o. + * Copyright (C) 2003 VMware, Inc. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_SYS_DISK_H +#include +#endif +#ifdef HAVE_LINUX_FD_H +#include +#include +#endif + +#if defined(__linux__) && defined(_IO) +#if !defined(BLKSSZGET) +#define BLKSSZGET _IO(0x12,104)/* get block device sector size */ +#endif +#if !defined(BLKPBSZGET) +#define BLKPBSZGET _IO(0x12,123)/* get block physical sector size */ +#endif +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +/* + * Returns the logical sector size of a device + */ +errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize) +{ + int fd; + + fd = ext2fs_open_file(file, O_RDONLY, 0); + if (fd < 0) + return errno; + +#ifdef BLKSSZGET + if (ioctl(fd, BLKSSZGET, sectsize) >= 0) { + close(fd); + return 0; + } +#endif +#ifdef DIOCGSECTORSIZE + if (ioctl(fd, DIOCGSECTORSIZE, sectsize) >= 0) { + close(fd); + return 0; + } +#endif + *sectsize = 0; + close(fd); + return 0; +} + +/* + * Return desired alignment for direct I/O + */ +int ext2fs_get_dio_alignment(int fd) +{ + int align = 0; + +#ifdef BLKSSZGET + if (ioctl(fd, BLKSSZGET, &align) < 0) + align = 0; +#endif +#ifdef DIOCGSECTORSIZE + if (align <= 0 && + ioctl(fd, DIOCGSECTORSIZE, &align) < 0) + align = 0; +#endif + +#ifdef _SC_PAGESIZE + if (align <= 0) + align = sysconf(_SC_PAGESIZE); +#endif +#ifdef HAVE_GETPAGESIZE + if (align <= 0) + align = getpagesize(); +#endif + if (align <= 0) + align = 4096; + + return align; +} + +/* + * Returns the physical sector size of a device + */ +errcode_t ext2fs_get_device_phys_sectsize(const char *file, int *sectsize) +{ + int fd; + + fd = ext2fs_open_file(file, O_RDONLY, 0); + if (fd < 0) + return errno; + +#ifdef BLKPBSZGET + if (ioctl(fd, BLKPBSZGET, sectsize) >= 0) { + close(fd); + return 0; + } +#endif +#ifdef DIOCGSECTORSIZE + /* This isn't really the physical sector size, but FreeBSD + * doesn't seem to have this concept. */ + if (ioctl(fd, DIOCGSECTORSIZE, sectsize) >= 0) { + close(fd); + return 0; + } +#endif + *sectsize = 0; + close(fd); + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/getsize.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/getsize.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,315 @@ +/* + * getsize.c --- get the size of a partition. + * + * Copyright (C) 1995, 1995 Theodore Ts'o. + * Copyright (C) 2003 VMware, Inc. + * + * Windows version of ext2fs_get_device_size by Chris Li, VMware. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_LINUX_FD_H +#include +#endif +#ifdef HAVE_SYS_DISKLABEL_H +#include +#endif +#ifdef HAVE_SYS_DISK_H +#include +#endif +#ifdef __linux__ +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#include + +#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE) +#define BLKGETSIZE _IO(0x12,96) /* return device size */ +#endif + +#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64) +#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */ +#endif + +#ifdef APPLE_DARWIN +#define BLKGETSIZE DKIOCGETBLOCKCOUNT32 +#endif /* APPLE_DARWIN */ + +#include "ext2_fs.h" +#include "ext2fs.h" + +#if defined(__CYGWIN__) || defined (WIN32) +#include "windows.h" +#include "winioctl.h" + +#if (_WIN32_WINNT >= 0x0500) +#define HAVE_GET_FILE_SIZE_EX 1 +#endif + +errcode_t ext2fs_get_device_size2(const char *file, int blocksize, + blk64_t *retblocks) +{ + HANDLE dev; + PARTITION_INFORMATION pi; + DISK_GEOMETRY gi; + DWORD retbytes; +#ifdef HAVE_GET_FILE_SIZE_EX + LARGE_INTEGER filesize; +#else + DWORD filesize; +#endif /* HAVE_GET_FILE_SIZE_EX */ + + dev = CreateFile(file, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE , + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (dev == INVALID_HANDLE_VALUE) + return EBADF; + if (DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO, + &pi, sizeof(PARTITION_INFORMATION), + &pi, sizeof(PARTITION_INFORMATION), + &retbytes, NULL)) { + + *retblocks = pi.PartitionLength.QuadPart / blocksize; + + } else if (DeviceIoControl(dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, + &gi, sizeof(DISK_GEOMETRY), + &gi, sizeof(DISK_GEOMETRY), + &retbytes, NULL)) { + + *retblocks = gi.BytesPerSector * + gi.SectorsPerTrack * + gi.TracksPerCylinder * + gi.Cylinders.QuadPart / blocksize; + +#ifdef HAVE_GET_FILE_SIZE_EX + } else if (GetFileSizeEx(dev, &filesize)) { + *retblocks = filesize.QuadPart / blocksize; + } +#else + } else { + filesize = GetFileSize(dev, NULL); + if (INVALID_FILE_SIZE != filesize) { + *retblocks = filesize / blocksize; + } + } +#endif /* HAVE_GET_FILE_SIZE_EX */ + + CloseHandle(dev); + return 0; +} + +#else + +static int valid_offset (int fd, ext2_loff_t offset) +{ + char ch; + + if (ext2fs_llseek (fd, offset, 0) < 0) + return 0; + if (read (fd, &ch, 1) < 1) + return 0; + return 1; +} + +/* + * Returns the number of blocks in a partition + */ +errcode_t ext2fs_get_device_size2(const char *file, int blocksize, + blk64_t *retblocks) +{ + int fd, rc = 0; + unsigned long long size64; + ext2_loff_t high, low; + + fd = ext2fs_open_file(file, O_RDONLY, 0); + if (fd < 0) + return errno; + +#if defined DKIOCGETBLOCKCOUNT && defined DKIOCGETBLOCKSIZE /* For Apple Darwin */ + unsigned int size; + + if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0 && + ioctl(fd, DKIOCGETBLOCKSIZE, &size) >= 0) { + *retblocks = size64 * size / blocksize; + goto out; + } +#endif + +#ifdef BLKGETSIZE64 + { + int valid_blkgetsize64 = 1; +#ifdef __linux__ + struct utsname ut; + + if ((uname(&ut) == 0) && + ((ut.release[0] == '2') && (ut.release[1] == '.') && + (ut.release[2] < '6') && (ut.release[3] == '.'))) + valid_blkgetsize64 = 0; +#endif + if (valid_blkgetsize64 && + ioctl(fd, BLKGETSIZE64, &size64) >= 0) { + *retblocks = size64 / blocksize; + goto out; + } + } +#endif /* BLKGETSIZE64 */ + +#ifdef BLKGETSIZE + { + unsigned long size; + + if (ioctl(fd, BLKGETSIZE, &size) >= 0) { + *retblocks = size / (blocksize / 512); + goto out; + } + } +#endif + +#ifdef FDGETPRM + { + struct floppy_struct this_floppy; + + if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) { + *retblocks = this_floppy.size / (blocksize / 512); + goto out; + } + } +#endif + +#ifdef HAVE_SYS_DISKLABEL_H + { + int part; + struct disklabel lab; + struct partition *pp; + char ch; + +#if defined(DIOCGMEDIASIZE) + { + off_t ms; + u_int bs; + if (ioctl(fd, DIOCGMEDIASIZE, &ms) >= 0) { + *retblocks = ms / blocksize; + goto out; + } + } +#elif defined(DIOCGDINFO) + /* old disklabel interface */ + part = strlen(file) - 1; + if (part >= 0) { + ch = file[part]; + if (isdigit(ch)) + part = 0; + else if (ch >= 'a' && ch <= 'h') + part = ch - 'a'; + else + part = -1; + } + if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) { + pp = &lab.d_partitions[part]; + if (pp->p_size) { + *retblocks = pp->p_size / (blocksize / 512); + goto out; + } + } +#endif /* defined(DIOCG*) */ + } +#endif /* HAVE_SYS_DISKLABEL_H */ + + { + ext2fs_struct_stat st; + + if (ext2fs_fstat(fd, &st) == 0) + if (S_ISREG(st.st_mode)) { + *retblocks = st.st_size / blocksize; + goto out; + } + } + + /* + * OK, we couldn't figure it out by using a specialized ioctl, + * which is generally the best way. So do binary search to + * find the size of the partition. + */ + low = 0; + for (high = 1024; valid_offset(fd, high); high *= 2) + low = high; + while (low < high - 1) { + const ext2_loff_t mid = (low + high) / 2; + + if (valid_offset (fd, mid)) + low = mid; + else + high = mid; + } + valid_offset(fd, 0); + size64 = low + 1; + *retblocks = size64 / blocksize; +out: + close(fd); + return rc; +} + +#endif /* WIN32 */ + +errcode_t ext2fs_get_device_size(const char *file, int blocksize, + blk_t *retblocks) +{ + errcode_t retval; + blk64_t blocks; + + retval = ext2fs_get_device_size2(file, blocksize, &blocks); + if (retval) + return retval; + if (blocks >= (1ULL << 32)) + return EFBIG; + *retblocks = (blk_t) blocks; + return 0; +} + +#ifdef DEBUG +int main(int argc, char **argv) +{ + blk_t blocks; + int retval; + + if (argc < 2) { + fprintf(stderr, "Usage: %s device\n", argv[0]); + exit(1); + } + + retval = ext2fs_get_device_size(argv[1], 1024, &blocks); + if (retval) { + com_err(argv[0], retval, + "while calling ext2fs_get_device_size"); + exit(1); + } + printf("Device %s has %u 1k blocks.\n", argv[1], blocks); + exit(0); +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/hashmap.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/hashmap.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,85 @@ +#include "hashmap.h" +#include + +uint32_t ext2fs_djb2_hash(const void *str, size_t size) +{ + int c; + const char *s = str; + uint32_t hash = 5381; + + while (size-- > 0) { + c = *s++; + hash = ((hash << 5) + hash) + c; + } + return hash; +} + +struct ext2fs_hashmap *ext2fs_hashmap_create( + uint32_t(*hash_fct)(const void*, size_t), + void(*free_fct)(void*), size_t size) +{ + struct ext2fs_hashmap *h = calloc(sizeof(struct ext2fs_hashmap) + + sizeof(struct ext2fs_hashmap_entry) * size, 1); + h->size = size; + h->free = free_fct; + h->hash = hash_fct; + h->first = h->last = NULL; + return h; +} + +void ext2fs_hashmap_add(struct ext2fs_hashmap *h, void *data, const void *key, + size_t key_len) +{ + uint32_t hash = h->hash(key, key_len) % h->size; + struct ext2fs_hashmap_entry *e = malloc(sizeof(*e)); + + e->data = data; + e->key = key; + e->key_len = key_len; + e->next = h->entries[hash]; + h->entries[hash] = e; + + e->list_prev = NULL; + e->list_next = h->first; + if (h->first) + h->first->list_prev = e; + h->first = e; + if (!h->last) + h->last = e; +} + +void *ext2fs_hashmap_lookup(struct ext2fs_hashmap *h, const void *key, + size_t key_len) +{ + struct ext2fs_hashmap_entry *iter; + uint32_t hash = h->hash(key, key_len) % h->size; + + for (iter = h->entries[hash]; iter; iter = iter->next) + if (iter->key_len == key_len && !memcmp(iter->key, key, key_len)) + return iter->data; + return NULL; +} + +void *ext2fs_hashmap_iter_in_order(struct ext2fs_hashmap *h, + struct ext2fs_hashmap_entry **it) +{ + *it = *it ? (*it)->list_next : h->first; + return *it ? (*it)->data : NULL; +} + +void ext2fs_hashmap_free(struct ext2fs_hashmap *h) +{ + size_t i; + + for (i = 0; i < h->size; ++i) { + struct ext2fs_hashmap_entry *it = h->entries[i]; + while (it) { + struct ext2fs_hashmap_entry *tmp = it->next; + if (h->free) + h->free(it->data); + free(it); + it = tmp; + } + } + free(h); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/i_block.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/i_block.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,90 @@ +/* + * i_block.c --- Manage the i_block field for i_blocks + * + * Copyright (C) 2008 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#include + +#include "ext2_fs.h" +#include "ext2fs.h" + +errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode, + blk64_t num_blocks) +{ + unsigned long long b = inode->i_blocks; + + if (ext2fs_has_feature_huge_file(fs->super)) + b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32; + + if (!ext2fs_has_feature_huge_file(fs->super) || + !(inode->i_flags & EXT4_HUGE_FILE_FL)) + num_blocks *= fs->blocksize / 512; + num_blocks *= EXT2FS_CLUSTER_RATIO(fs); + + b += num_blocks; + + if (ext2fs_has_feature_huge_file(fs->super)) + inode->osd2.linux2.l_i_blocks_hi = b >> 32; + else if (b > 0xFFFFFFFF) + return EOVERFLOW; + inode->i_blocks = b & 0xFFFFFFFF; + return 0; +} + +errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode, + blk64_t num_blocks) +{ + unsigned long long b = inode->i_blocks; + + if (ext2fs_has_feature_huge_file(fs->super)) + b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32; + + if (!ext2fs_has_feature_huge_file(fs->super) || + !(inode->i_flags & EXT4_HUGE_FILE_FL)) + num_blocks *= fs->blocksize / 512; + num_blocks *= EXT2FS_CLUSTER_RATIO(fs); + + if (num_blocks > b) + return EOVERFLOW; + + b -= num_blocks; + + if (ext2fs_has_feature_huge_file(fs->super)) + inode->osd2.linux2.l_i_blocks_hi = b >> 32; + inode->i_blocks = b & 0xFFFFFFFF; + return 0; +} + +errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t b) +{ + if (!ext2fs_has_feature_huge_file(fs->super) || + !(inode->i_flags & EXT4_HUGE_FILE_FL)) + b *= fs->blocksize / 512; + b *= EXT2FS_CLUSTER_RATIO(fs); + + inode->i_blocks = b & 0xFFFFFFFF; + if (ext2fs_has_feature_huge_file(fs->super)) + inode->osd2.linux2.l_i_blocks_hi = b >> 32; + else if (b >> 32) + return EOVERFLOW; + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/ind_block.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/ind_block.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,67 @@ +/* + * ind_block.c --- indirect block I/O routines + * + * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf) +{ + errcode_t retval; +#ifdef WORDS_BIGENDIAN + blk_t *block_nr; + int i; + int limit = fs->blocksize >> 2; +#endif + + if ((fs->flags & EXT2_FLAG_IMAGE_FILE) && + (fs->io != fs->image_io)) + memset(buf, 0, fs->blocksize); + else { + retval = io_channel_read_blk(fs->io, blk, 1, buf); + if (retval) + return retval; + } +#ifdef WORDS_BIGENDIAN + block_nr = (blk_t *) buf; + for (i = 0; i < limit; i++, block_nr++) + *block_nr = ext2fs_swab32(*block_nr); +#endif + return 0; +} + +errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf) +{ +#ifdef WORDS_BIGENDIAN + blk_t *block_nr; + int i; + int limit = fs->blocksize >> 2; +#endif + + if (fs->flags & EXT2_FLAG_IMAGE_FILE) + return 0; + +#ifdef WORDS_BIGENDIAN + block_nr = (blk_t *) buf; + for (i = 0; i < limit; i++, block_nr++) + *block_nr = ext2fs_swab32(*block_nr); +#endif + return io_channel_write_blk(fs->io, blk, 1, buf); +} + + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/initialize.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/initialize.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,570 @@ +/* + * initialize.c --- initialize a filesystem handle given superblock + * parameters. Used by mke2fs when initializing a filesystem. + * + * Copyright (C) 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#if defined(__linux__) && defined(EXT2_OS_LINUX) +#define CREATOR_OS EXT2_OS_LINUX +#else +#if defined(__GNU__) && defined(EXT2_OS_HURD) +#define CREATOR_OS EXT2_OS_HURD +#else +#if defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) +#define CREATOR_OS EXT2_OS_FREEBSD +#else +#if defined(LITES) && defined(EXT2_OS_LITES) +#define CREATOR_OS EXT2_OS_LITES +#else +#define CREATOR_OS EXT2_OS_LINUX /* by default */ +#endif /* defined(LITES) && defined(EXT2_OS_LITES) */ +#endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */ +#endif /* defined(__GNU__) && defined(EXT2_OS_HURD) */ +#endif /* defined(__linux__) && defined(EXT2_OS_LINUX) */ + +/* + * Calculate the number of GDT blocks to reserve for online filesystem growth. + * The absolute maximum number of GDT blocks we can reserve is determined by + * the number of block pointers that can fit into a single block. + */ +static unsigned int calc_reserved_gdt_blocks(ext2_filsys fs) +{ + struct ext2_super_block *sb = fs->super; + unsigned long bpg = sb->s_blocks_per_group; + unsigned int gdpb = EXT2_DESC_PER_BLOCK(sb); + unsigned long max_blocks = 0xffffffff; + unsigned long rsv_groups; + unsigned int rsv_gdb; + + /* We set it at 1024x the current filesystem size, or + * the upper block count limit (2^32), whichever is lower. + */ + if (ext2fs_blocks_count(sb) < max_blocks / 1024) + max_blocks = ext2fs_blocks_count(sb) * 1024; + /* + * ext2fs_div64_ceil() is unnecessary because max_blocks is + * max _GDT_ blocks, which is limited to 32 bits. + */ + rsv_groups = ext2fs_div_ceil(max_blocks - sb->s_first_data_block, bpg); + rsv_gdb = ext2fs_div_ceil(rsv_groups, gdpb) - fs->desc_blocks; + if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb)) + rsv_gdb = EXT2_ADDR_PER_BLOCK(sb); +#ifdef RES_GDT_DEBUG + printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %u\n", + max_blocks, rsv_groups, rsv_gdb); +#endif + + return rsv_gdb; +} + +errcode_t ext2fs_initialize(const char *name, int flags, + struct ext2_super_block *param, + io_manager manager, ext2_filsys *ret_fs) +{ + ext2_filsys fs; + errcode_t retval; + struct ext2_super_block *super; + unsigned int rem; + unsigned int overhead = 0; + unsigned int ipg; + dgrp_t i; + blk64_t free_blocks; + blk_t numblocks; + int rsv_gdt; + int csum_flag; + int bigalloc_flag; + int io_flags; + int has_bg; + unsigned reserved_inos; + char *buf = 0; + char c; + double reserved_ratio; + char *time_env; + + if (!param || !ext2fs_blocks_count(param)) + return EXT2_ET_INVALID_ARGUMENT; + + retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs); + if (retval) + return retval; + + memset(fs, 0, sizeof(struct struct_ext2_filsys)); + fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS; + fs->flags = flags | EXT2_FLAG_RW; + fs->umask = 022; + fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; +#ifdef WORDS_BIGENDIAN + fs->flags |= EXT2_FLAG_SWAP_BYTES; +#endif + + time_env = getenv("E2FSPROGS_FAKE_TIME"); + if (time_env) + fs->now = strtoul(time_env, NULL, 0); + + io_flags = IO_FLAG_RW; + if (flags & EXT2_FLAG_EXCLUSIVE) + io_flags |= IO_FLAG_EXCLUSIVE; + if (flags & EXT2_FLAG_DIRECT_IO) + io_flags |= IO_FLAG_DIRECT_IO; + io_flags |= O_BINARY; + retval = manager->open(name, io_flags, &fs->io); + if (retval) + goto cleanup; + fs->image_io = fs->io; + fs->io->app_data = fs; + retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name); + if (retval) + goto cleanup; + + strcpy(fs->device_name, name); + retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super); + if (retval) + goto cleanup; + fs->super = super; + + memset(super, 0, SUPERBLOCK_SIZE); + +#define set_field(field, default) (super->field = param->field ? \ + param->field : (default)) +#define assign_field(field) (super->field = param->field) + + super->s_magic = EXT2_SUPER_MAGIC; + super->s_state = EXT2_VALID_FS; + + bigalloc_flag = ext2fs_has_feature_bigalloc(param); + + assign_field(s_log_block_size); + + if (bigalloc_flag) { + set_field(s_log_cluster_size, super->s_log_block_size+4); + if (super->s_log_block_size > super->s_log_cluster_size) { + retval = EXT2_ET_INVALID_ARGUMENT; + goto cleanup; + } + } else + super->s_log_cluster_size = super->s_log_block_size; + + set_field(s_first_data_block, super->s_log_cluster_size ? 0 : 1); + set_field(s_max_mnt_count, 0); + set_field(s_errors, EXT2_ERRORS_DEFAULT); + set_field(s_feature_compat, 0); + set_field(s_feature_incompat, 0); + set_field(s_feature_ro_compat, 0); + set_field(s_default_mount_opts, 0); + set_field(s_first_meta_bg, 0); + set_field(s_raid_stride, 0); /* default stride size: 0 */ + set_field(s_raid_stripe_width, 0); /* default stripe width: 0 */ + set_field(s_log_groups_per_flex, 0); + set_field(s_flags, 0); + assign_field(s_backup_bgs[0]); + assign_field(s_backup_bgs[1]); + if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) { + retval = EXT2_ET_UNSUPP_FEATURE; + goto cleanup; + } + if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) { + retval = EXT2_ET_RO_UNSUPP_FEATURE; + goto cleanup; + } + + set_field(s_rev_level, EXT2_GOOD_OLD_REV); + if (super->s_rev_level >= EXT2_DYNAMIC_REV) { + set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO); + set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE); + if (super->s_inode_size >= sizeof(struct ext2_inode_large)) { + int extra_isize = sizeof(struct ext2_inode_large) - + EXT2_GOOD_OLD_INODE_SIZE; + set_field(s_min_extra_isize, extra_isize); + set_field(s_want_extra_isize, extra_isize); + } + } else { + super->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; + super->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; + } + + set_field(s_checkinterval, 0); + super->s_mkfs_time = super->s_lastcheck = fs->now ? fs->now : time(NULL); + + super->s_creator_os = CREATOR_OS; + + fs->fragsize = fs->blocksize = EXT2_BLOCK_SIZE(super); + fs->cluster_ratio_bits = super->s_log_cluster_size - + super->s_log_block_size; + + if (bigalloc_flag) { + unsigned long long bpg; + + if (param->s_blocks_per_group && + param->s_clusters_per_group && + ((param->s_clusters_per_group * EXT2FS_CLUSTER_RATIO(fs)) != + param->s_blocks_per_group)) { + retval = EXT2_ET_INVALID_ARGUMENT; + goto cleanup; + } + if (param->s_clusters_per_group) + assign_field(s_clusters_per_group); + else if (param->s_blocks_per_group) + super->s_clusters_per_group = + param->s_blocks_per_group / + EXT2FS_CLUSTER_RATIO(fs); + else if (super->s_log_cluster_size + 15 < 32) + super->s_clusters_per_group = fs->blocksize * 8; + else + super->s_clusters_per_group = (fs->blocksize - 1) * 8; + if (super->s_clusters_per_group > EXT2_MAX_CLUSTERS_PER_GROUP(super)) + super->s_clusters_per_group = EXT2_MAX_CLUSTERS_PER_GROUP(super); + bpg = EXT2FS_C2B(fs, + (unsigned long long) super->s_clusters_per_group); + if (bpg >= (((unsigned long long) 1) << 32)) { + retval = EXT2_ET_INVALID_ARGUMENT; + goto cleanup; + } + super->s_blocks_per_group = bpg; + } else { + set_field(s_blocks_per_group, fs->blocksize * 8); + if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super)) + super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super); + super->s_clusters_per_group = super->s_blocks_per_group; + } + + ext2fs_blocks_count_set(super, ext2fs_blocks_count(param) & + ~((blk64_t) EXT2FS_CLUSTER_MASK(fs))); + ext2fs_r_blocks_count_set(super, ext2fs_r_blocks_count(param)); + if (ext2fs_r_blocks_count(super) >= ext2fs_blocks_count(param)) { + retval = EXT2_ET_INVALID_ARGUMENT; + goto cleanup; + } + + set_field(s_mmp_update_interval, 0); + + /* + * If we're creating an external journal device, we don't need + * to bother with the rest. + */ + if (ext2fs_has_feature_journal_dev(super)) { + fs->group_desc_count = 0; + ext2fs_mark_super_dirty(fs); + *ret_fs = fs; + return 0; + } + +retry: + fs->group_desc_count = (dgrp_t) ext2fs_div64_ceil( + ext2fs_blocks_count(super) - super->s_first_data_block, + EXT2_BLOCKS_PER_GROUP(super)); + if (fs->group_desc_count == 0) { + retval = EXT2_ET_TOOSMALL; + goto cleanup; + } + + set_field(s_desc_size, + ext2fs_has_feature_64bit(super) ? + EXT2_MIN_DESC_SIZE_64BIT : 0); + + fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count, + EXT2_DESC_PER_BLOCK(super)); + + i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize; + + if (ext2fs_has_feature_64bit(super) && + (ext2fs_blocks_count(super) / i) >= (1ULL << 32)) + set_field(s_inodes_count, ~0U); + else + set_field(s_inodes_count, ext2fs_blocks_count(super) / i); + + /* + * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so + * that we have enough inodes for the filesystem(!) + */ + if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1) + super->s_inodes_count = EXT2_FIRST_INODE(super)+1; + + /* + * There should be at least as many inodes as the user + * requested. Figure out how many inodes per group that + * should be. But make sure that we don't allocate more than + * one bitmap's worth of inodes each group. + */ + ipg = ext2fs_div_ceil(super->s_inodes_count, fs->group_desc_count); + if (ipg > fs->blocksize * 8) { + if (!bigalloc_flag && super->s_blocks_per_group >= 256) { + /* Try again with slightly different parameters */ + super->s_blocks_per_group -= 8; + ext2fs_blocks_count_set(super, + ext2fs_blocks_count(param)); + super->s_clusters_per_group = super->s_blocks_per_group; + goto retry; + } else { + retval = EXT2_ET_TOO_MANY_INODES; + goto cleanup; + } + } + + if (ipg > (unsigned) EXT2_MAX_INODES_PER_GROUP(super)) + ipg = EXT2_MAX_INODES_PER_GROUP(super); + +ipg_retry: + super->s_inodes_per_group = ipg; + + /* + * Make sure the number of inodes per group completely fills + * the inode table blocks in the descriptor. If not, add some + * additional inodes/group. Waste not, want not... + */ + fs->inode_blocks_per_group = (((super->s_inodes_per_group * + EXT2_INODE_SIZE(super)) + + EXT2_BLOCK_SIZE(super) - 1) / + EXT2_BLOCK_SIZE(super)); + super->s_inodes_per_group = ((fs->inode_blocks_per_group * + EXT2_BLOCK_SIZE(super)) / + EXT2_INODE_SIZE(super)); + /* + * Finally, make sure the number of inodes per group is a + * multiple of 8. This is needed to simplify the bitmap + * splicing code. + */ + if (super->s_inodes_per_group < 8) + super->s_inodes_per_group = 8; + super->s_inodes_per_group &= ~7; + fs->inode_blocks_per_group = (((super->s_inodes_per_group * + EXT2_INODE_SIZE(super)) + + EXT2_BLOCK_SIZE(super) - 1) / + EXT2_BLOCK_SIZE(super)); + + /* + * adjust inode count to reflect the adjusted inodes_per_group + */ + if ((__u64)super->s_inodes_per_group * fs->group_desc_count > ~0U) { + ipg--; + goto ipg_retry; + } + super->s_inodes_count = super->s_inodes_per_group * + fs->group_desc_count; + super->s_free_inodes_count = super->s_inodes_count; + + /* + * check the number of reserved group descriptor table blocks + */ + if (ext2fs_has_feature_resize_inode(super)) + rsv_gdt = calc_reserved_gdt_blocks(fs); + else + rsv_gdt = 0; + set_field(s_reserved_gdt_blocks, rsv_gdt); + if (super->s_reserved_gdt_blocks > EXT2_ADDR_PER_BLOCK(super)) { + retval = EXT2_ET_RES_GDT_BLOCKS; + goto cleanup; + } + /* Enable meta_bg if we'd lose more than 3/4 of a BG to GDT blocks. */ + if (super->s_reserved_gdt_blocks + fs->desc_blocks > + super->s_blocks_per_group * 3 / 4) { + ext2fs_set_feature_meta_bg(fs->super); + ext2fs_clear_feature_resize_inode(fs->super); + set_field(s_reserved_gdt_blocks, 0); + } + + /* + * Calculate the maximum number of bookkeeping blocks per + * group. It includes the superblock, the block group + * descriptors, the block bitmap, the inode bitmap, the inode + * table, and the reserved gdt blocks. + */ + overhead = (int) (3 + fs->inode_blocks_per_group + + super->s_reserved_gdt_blocks); + + if (ext2fs_has_feature_meta_bg(fs->super)) + overhead++; + else + overhead += fs->desc_blocks; + + /* This can only happen if the user requested too many inodes */ + if (overhead > super->s_blocks_per_group) { + retval = EXT2_ET_TOO_MANY_INODES; + goto cleanup; + } + + /* + * See if the last group is big enough to support the + * necessary data structures. If not, we need to get rid of + * it. We need to recalculate the overhead for the last block + * group, since it might or might not have a superblock + * backup. + */ + overhead = (int) (2 + fs->inode_blocks_per_group); + has_bg = 0; + if (ext2fs_has_feature_sparse_super2(super)) { + /* + * We have to do this manually since + * super->s_backup_bgs hasn't been set up yet. + */ + if (fs->group_desc_count == 2) + has_bg = param->s_backup_bgs[0] != 0; + else + has_bg = param->s_backup_bgs[1] != 0; + } else + has_bg = ext2fs_bg_has_super(fs, fs->group_desc_count - 1); + if (has_bg) + overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks; + rem = ((ext2fs_blocks_count(super) - super->s_first_data_block) % + super->s_blocks_per_group); + if ((fs->group_desc_count == 1) && rem && (rem < overhead)) { + retval = EXT2_ET_TOOSMALL; + goto cleanup; + } + if (rem && (rem < overhead+50)) { + ext2fs_blocks_count_set(super, ext2fs_blocks_count(super) - + rem); + /* + * If blocks count is changed, we need to recalculate + * reserved blocks count not to exceed 50%. + */ + reserved_ratio = 100.0 * ext2fs_r_blocks_count(param) / + ext2fs_blocks_count(param); + ext2fs_r_blocks_count_set(super, reserved_ratio * + ext2fs_blocks_count(super) / 100.0); + + goto retry; + } + + /* + * At this point we know how big the filesystem will be. So + * we can do any and all allocations that depend on the block + * count. + */ + + /* Set up the locations of the backup superblocks */ + if (ext2fs_has_feature_sparse_super2(super)) { + if (super->s_backup_bgs[0] >= fs->group_desc_count) + super->s_backup_bgs[0] = fs->group_desc_count - 1; + if (super->s_backup_bgs[1] >= fs->group_desc_count) + super->s_backup_bgs[1] = fs->group_desc_count - 1; + if (super->s_backup_bgs[0] == super->s_backup_bgs[1]) + super->s_backup_bgs[1] = 0; + if (super->s_backup_bgs[0] > super->s_backup_bgs[1]) { + __u32 t = super->s_backup_bgs[0]; + super->s_backup_bgs[0] = super->s_backup_bgs[1]; + super->s_backup_bgs[1] = t; + } + } + + retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf); + if (retval) + goto cleanup; + + strcpy(buf, "block bitmap for "); + strcat(buf, fs->device_name); + retval = ext2fs_allocate_subcluster_bitmap(fs, buf, &fs->block_map); + if (retval) + goto cleanup; + + strcpy(buf, "inode bitmap for "); + strcat(buf, fs->device_name); + retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map); + if (retval) + goto cleanup; + + ext2fs_free_mem(&buf); + + retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize, + &fs->group_desc); + if (retval) + goto cleanup; + + memset(fs->group_desc, 0, (size_t) fs->desc_blocks * fs->blocksize); + + /* + * Reserve the superblock and group descriptors for each + * group, and fill in the correct group statistics for group. + * Note that although the block bitmap, inode bitmap, and + * inode table have not been allocated (and in fact won't be + * by this routine), they are accounted for nevertheless. + * + * If FLEX_BG meta-data grouping is used, only account for the + * superblock and group descriptors (the inode tables and + * bitmaps will be accounted for when allocated). + */ + free_blocks = 0; + csum_flag = ext2fs_has_group_desc_csum(fs); + reserved_inos = super->s_first_ino; + for (i = 0; i < fs->group_desc_count; i++) { + /* + * Don't set the BLOCK_UNINIT group for the last group + * because the block bitmap needs to be padded. + */ + if (csum_flag) { + if (i != fs->group_desc_count - 1) + ext2fs_bg_flags_set(fs, i, + EXT2_BG_BLOCK_UNINIT); + ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT); + numblocks = super->s_inodes_per_group; + if (reserved_inos) { + if (numblocks > reserved_inos) { + numblocks -= reserved_inos; + reserved_inos = 0; + } else { + reserved_inos -= numblocks; + numblocks = 0; + } + } + ext2fs_bg_itable_unused_set(fs, i, numblocks); + } + numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map); + if (fs->super->s_log_groups_per_flex) + numblocks += 2 + fs->inode_blocks_per_group; + + free_blocks += numblocks; + ext2fs_bg_free_blocks_count_set(fs, i, numblocks); + ext2fs_bg_free_inodes_count_set(fs, i, fs->super->s_inodes_per_group); + ext2fs_bg_used_dirs_count_set(fs, i, 0); + ext2fs_group_desc_csum_set(fs, i); + } + free_blocks &= ~EXT2FS_CLUSTER_MASK(fs); + ext2fs_free_blocks_count_set(super, free_blocks); + + c = (char) 255; + if (((int) c) == -1) { + super->s_flags |= EXT2_FLAGS_SIGNED_HASH; + } else { + super->s_flags |= EXT2_FLAGS_UNSIGNED_HASH; + } + + ext2fs_mark_super_dirty(fs); + ext2fs_mark_bb_dirty(fs); + ext2fs_mark_ib_dirty(fs); + + io_channel_set_blksize(fs->io, fs->blocksize); + + *ret_fs = fs; + return 0; +cleanup: + free(buf); + ext2fs_free(fs); + return retval; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/inline.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/inline.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,118 @@ +/* + * inline.c --- Includes the inlined functions defined in the header + * files as standalone functions, in case the application program + * is compiled with inlining turned off. + * + * Copyright (C) 1993, 1994 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 /* for posix_memalign() */ +#endif + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_MALLOC_H +#include +#endif + +#include "ext2_fs.h" +#define INCLUDE_INLINE_FUNCS +#include "ext2fs.h" + +/* + * We used to define this as an inline, but since we are now using + * autoconf-defined #ifdef's, we need to export this as a + * library-provided function exclusively. + */ +errcode_t ext2fs_get_memalign(unsigned long size, + unsigned long align, void *ptr) +{ + errcode_t retval = 0; + void **p = ptr; + + if (align < 8) + align = 8; +#ifdef HAVE_POSIX_MEMALIGN + retval = posix_memalign(p, align, size); + if (retval == ENOMEM) + return EXT2_ET_NO_MEMORY; +#else /* !HAVE_POSIX_MEMALIGN */ +#ifdef HAVE_MEMALIGN + *p = memalign(align, size); + if (*p == NULL) { + if (errno) + return errno; + else + return EXT2_ET_NO_MEMORY; + } +#else /* !HAVE_MEMALIGN */ +#ifdef HAVE_VALLOC + if (align > sizeof(long long)) + *p = valloc(size); + else +#endif + *p = malloc(size); + if ((uintptr_t) *p & (align - 1)) { + free(*p); + *p = 0; + } + if (*p == 0) + return EXT2_ET_NO_MEMORY; +#endif /* HAVE_MEMALIGN */ +#endif /* HAVE_POSIX_MEMALIGN */ + return retval; +} + +#ifdef DEBUG +static int isaligned(void *ptr, unsigned long align) +{ + return (((unsigned long) ptr & (align - 1)) == 0); +} + +static errcode_t test_memalign(unsigned long align) +{ + void *ptr = 0; + errcode_t retval; + + retval = ext2fs_get_memalign(32, align, &ptr); + if (!retval && !isaligned(ptr, align)) + retval = EINVAL; + free(ptr); + printf("tst_memalign(%lu) is %s\n", align, + retval ? error_message(retval) : "OK"); + return retval; +} + +int main(int argc, char **argv) +{ + int err = 0; + + if (test_memalign(4)) + err++; + if (test_memalign(32)) + err++; + if (test_memalign(1024)) + err++; + if (test_memalign(4096)) + err++; + return err; +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/inline_data.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/inline_data.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,842 @@ +/* + * inline_data.c --- data in inode + * + * Copyright (C) 2012 Zheng Liu + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include /* for PATH_MAX */ + +#include "ext2_fs.h" +#include "ext2_ext_attr.h" + +#include "ext2fs.h" +#include "ext2fsP.h" + +struct ext2_inline_data { + ext2_filsys fs; + ext2_ino_t ino; + size_t ea_size; /* the size of inline data in ea area */ + void *ea_data; +}; + +static errcode_t ext2fs_inline_data_ea_set(struct ext2_inline_data *data) +{ + struct ext2_xattr_handle *handle; + errcode_t retval; + + retval = ext2fs_xattrs_open(data->fs, data->ino, &handle); + if (retval) + return retval; + + retval = ext2fs_xattrs_read(handle); + if (retval) + goto err; + + retval = ext2fs_xattr_set(handle, "system.data", + data->ea_data, data->ea_size); +err: + (void) ext2fs_xattrs_close(&handle); + return retval; +} + +static errcode_t ext2fs_inline_data_ea_get(struct ext2_inline_data *data) +{ + struct ext2_xattr_handle *handle; + errcode_t retval; + + data->ea_size = 0; + data->ea_data = 0; + + retval = ext2fs_xattrs_open(data->fs, data->ino, &handle); + if (retval) + return retval; + + retval = ext2fs_xattrs_read(handle); + if (retval) + goto err; + + retval = ext2fs_xattr_get(handle, "system.data", + (void **)&data->ea_data, &data->ea_size); + if (retval == EXT2_ET_EA_KEY_NOT_FOUND) { + data->ea_size = 0; + data->ea_data = NULL; + retval = 0; + } else if (retval) + goto err; + +err: + (void) ext2fs_xattrs_close(&handle); + return retval; +} + +errcode_t ext2fs_inline_data_init(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_inline_data data; + char empty[1] = { '\0' }; + + data.fs = fs; + data.ino = ino; + data.ea_size = 0; + data.ea_data = empty; + return ext2fs_inline_data_ea_set(&data); +} + +errcode_t ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino, size_t *size) +{ + struct ext2_inode inode; + struct ext2_inline_data data; + errcode_t retval; + + retval = ext2fs_read_inode(fs, ino, &inode); + if (retval) + return retval; + + if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) + return EXT2_ET_NO_INLINE_DATA; + + data.fs = fs; + data.ino = ino; + retval = ext2fs_inline_data_ea_get(&data); + if (retval) + return retval; + + *size = EXT4_MIN_INLINE_DATA_SIZE + data.ea_size; + return ext2fs_free_mem(&data.ea_data); +} + +int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino, + void *priv_data) +{ + struct dir_context *ctx; + struct ext2_inode inode; + struct ext2_dir_entry dirent; + struct ext2_inline_data data; + int ret = BLOCK_ABORT; + e2_blkcnt_t blockcnt = 0; + char *old_buf; + unsigned int old_buflen; + int old_flags; + + ctx = (struct dir_context *)priv_data; + old_buf = ctx->buf; + old_buflen = ctx->buflen; + old_flags = ctx->flags; + ctx->flags |= DIRENT_FLAG_INCLUDE_INLINE_DATA; + + ctx->errcode = ext2fs_read_inode(fs, ino, &inode); + if (ctx->errcode) + goto out; + + if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) { + ctx->errcode = EXT2_ET_NO_INLINE_DATA; + goto out; + } + + if (!LINUX_S_ISDIR(inode.i_mode)) { + ctx->errcode = EXT2_ET_NO_DIRECTORY; + goto out; + } + ret = 0; + + /* we first check '.' and '..' dir */ + dirent.inode = ino; + dirent.name_len = 1; + ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent); + dirent.name[0] = '.'; + dirent.name[1] = '\0'; + ctx->buf = (char *)&dirent; + ext2fs_get_rec_len(fs, &dirent, &ctx->buflen); + ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); + if (ret & BLOCK_ABORT) + goto out; + + dirent.inode = ext2fs_le32_to_cpu(inode.i_block[0]); + dirent.name_len = 2; + ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent); + dirent.name[0] = '.'; + dirent.name[1] = '.'; + dirent.name[2] = '\0'; + ctx->buf = (char *)&dirent; + ext2fs_get_rec_len(fs, &dirent, &ctx->buflen); + ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); + if (ret & BLOCK_INLINE_DATA_CHANGED) { + errcode_t err; + + inode.i_block[0] = ext2fs_cpu_to_le32(dirent.inode); + err = ext2fs_write_inode(fs, ino, &inode); + if (err) + goto out; + ret &= ~BLOCK_INLINE_DATA_CHANGED; + } + if (ret & BLOCK_ABORT) + goto out; + + ctx->buf = (char *)inode.i_block + EXT4_INLINE_DATA_DOTDOT_SIZE; + ctx->buflen = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE; +#ifdef WORDS_BIGENDIAN + ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0); + if (ctx->errcode) { + ret |= BLOCK_ABORT; + goto out; + } +#endif + ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); + if (ret & BLOCK_INLINE_DATA_CHANGED) { +#ifdef WORDS_BIGENDIAN + ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf, + ctx->buflen, 0); + if (ctx->errcode) { + ret |= BLOCK_ABORT; + goto out; + } +#endif + ctx->errcode = ext2fs_write_inode(fs, ino, &inode); + if (ctx->errcode) + ret |= BLOCK_ABORT; + ret &= ~BLOCK_INLINE_DATA_CHANGED; + } + if (ret & BLOCK_ABORT) + goto out; + + data.fs = fs; + data.ino = ino; + ctx->errcode = ext2fs_inline_data_ea_get(&data); + if (ctx->errcode) { + ret |= BLOCK_ABORT; + goto out; + } + if (data.ea_size <= 0) + goto out1; + + ctx->buf = data.ea_data; + ctx->buflen = data.ea_size; +#ifdef WORDS_BIGENDIAN + ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0); + if (ctx->errcode) { + ret |= BLOCK_ABORT; + goto out1; + } +#endif + + ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); + if (ret & BLOCK_INLINE_DATA_CHANGED) { +#ifdef WORDS_BIGENDIAN + ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf, + ctx->buflen, 0); + if (ctx->errcode) { + ret |= BLOCK_ABORT; + goto out1; + } +#endif + ctx->errcode = ext2fs_inline_data_ea_set(&data); + if (ctx->errcode) + ret |= BLOCK_ABORT; + } + +out1: + ext2fs_free_mem(&data.ea_data); +out: + ctx->buf = old_buf; + ctx->buflen = old_buflen; + ctx->flags = old_flags; + ret &= ~(BLOCK_ABORT | BLOCK_INLINE_DATA_CHANGED); + return ret; +} + +errcode_t ext2fs_inline_data_ea_remove(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_xattr_handle *handle; + errcode_t retval; + + retval = ext2fs_xattrs_open(fs, ino, &handle); + if (retval) + return retval; + + retval = ext2fs_xattrs_read(handle); + if (retval) + goto err; + + retval = ext2fs_xattr_remove(handle, "system.data"); +err: + (void) ext2fs_xattrs_close(&handle); + return retval; +} + +static errcode_t ext2fs_inline_data_convert_dir(ext2_filsys fs, ext2_ino_t ino, + char *bbuf, char *ibuf, int size) +{ + struct ext2_dir_entry *dir, *dir2; + struct ext2_dir_entry_tail *t; + errcode_t retval; + int offset; + unsigned int rec_len; + int csum_size = 0; + int filetype = 0; + + if (ext2fs_has_feature_metadata_csum(fs->super)) + csum_size = sizeof(struct ext2_dir_entry_tail); + + /* Create '.' and '..' */ + if (ext2fs_has_feature_filetype(fs->super)) + filetype = EXT2_FT_DIR; + + /* + * Set up entry for '.' + */ + dir = (struct ext2_dir_entry *) bbuf; + dir->inode = ino; + ext2fs_dirent_set_name_len(dir, 1); + ext2fs_dirent_set_file_type(dir, filetype); + dir->name[0] = '.'; + rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1); + dir->rec_len = EXT2_DIR_REC_LEN(1); + + /* + * Set up entry for '..' + */ + dir = (struct ext2_dir_entry *) (bbuf + dir->rec_len); + dir->rec_len = EXT2_DIR_REC_LEN(2); + dir->inode = ext2fs_le32_to_cpu(((__u32 *)ibuf)[0]); + ext2fs_dirent_set_name_len(dir, 2); + ext2fs_dirent_set_file_type(dir, filetype); + dir->name[0] = '.'; + dir->name[1] = '.'; + + /* + * Adjust the last rec_len + */ + offset = EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2); + dir = (struct ext2_dir_entry *) (bbuf + offset); + memcpy(bbuf + offset, ibuf + EXT4_INLINE_DATA_DOTDOT_SIZE, + size - EXT4_INLINE_DATA_DOTDOT_SIZE); + size += EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) - + EXT4_INLINE_DATA_DOTDOT_SIZE; + + do { + dir2 = dir; + retval = ext2fs_get_rec_len(fs, dir, &rec_len); + if (retval) + goto err; + offset += rec_len; + dir = (struct ext2_dir_entry *) (bbuf + offset); + } while (offset < size); + rec_len += fs->blocksize - csum_size - offset; + retval = ext2fs_set_rec_len(fs, rec_len, dir2); + if (retval) + goto err; + + if (csum_size) { + t = EXT2_DIRENT_TAIL(bbuf, fs->blocksize); + ext2fs_initialize_dirent_tail(fs, t); + } + +err: + return retval; +} + +static errcode_t +ext2fs_inline_data_dir_expand(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, char *buf, size_t size) +{ + errcode_t retval; + blk64_t blk; + char *blk_buf; + + retval = ext2fs_get_memzero(fs->blocksize, &blk_buf); + if (retval) + return retval; + +#ifdef WORDS_BIGENDIAN + retval = ext2fs_dirent_swab_in2(fs, buf + EXT4_INLINE_DATA_DOTDOT_SIZE, + size, 0); + if (retval) + goto errout; +#endif + + /* Adjust the rec_len */ + retval = ext2fs_inline_data_convert_dir(fs, ino, blk_buf, buf, size); + if (retval) + goto errout; + /* Allocate a new block */ + retval = ext2fs_new_block2(fs, 0, 0, &blk); + if (retval) + goto errout; + retval = ext2fs_write_dir_block4(fs, blk, blk_buf, 0, ino); + if (retval) + goto errout; + + /* Update inode */ + if (ext2fs_has_feature_extents(fs->super)) + inode->i_flags |= EXT4_EXTENTS_FL; + inode->i_flags &= ~EXT4_INLINE_DATA_FL; + retval = ext2fs_iblk_add_blocks(fs, inode, 1); + if (retval) + goto errout; + inode->i_size = fs->blocksize; + retval = ext2fs_bmap2(fs, ino, inode, 0, BMAP_SET, 0, 0, &blk); + if (retval) + goto errout; + retval = ext2fs_write_inode(fs, ino, inode); + if (retval) + goto errout; + ext2fs_block_alloc_stats(fs, blk, +1); + +errout: + ext2fs_free_mem(&blk_buf); + return retval; +} + +static errcode_t +ext2fs_inline_data_file_expand(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, char *buf, size_t size) +{ + ext2_file_t e2_file; + errcode_t retval; + + /* Update inode */ + memset(inode->i_block, 0, sizeof(inode->i_block)); + if (ext2fs_has_feature_extents(fs->super)) { + ext2_extent_handle_t handle; + + inode->i_flags &= ~EXT4_EXTENTS_FL; + retval = ext2fs_extent_open2(fs, ino, inode, &handle); + if (retval) + return retval; + ext2fs_extent_free(handle); + } + inode->i_flags &= ~EXT4_INLINE_DATA_FL; + inode->i_size = 0; + retval = ext2fs_write_inode(fs, ino, inode); + if (retval) + return retval; + + /* Write out the block buffer */ + retval = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &e2_file); + if (retval) + return retval; + retval = ext2fs_file_write(e2_file, buf, size, 0); + ext2fs_file_close(e2_file); + return retval; +} + +errcode_t ext2fs_inline_data_expand(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_inode inode; + struct ext2_inline_data data; + errcode_t retval; + size_t inline_size; + char *inline_buf = 0; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + retval = ext2fs_read_inode(fs, ino, &inode); + if (retval) + return retval; + + if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) + return EXT2_ET_NO_INLINE_DATA; + + data.fs = fs; + data.ino = ino; + retval = ext2fs_inline_data_ea_get(&data); + if (retval) + return retval; + inline_size = data.ea_size + EXT4_MIN_INLINE_DATA_SIZE; + retval = ext2fs_get_mem(inline_size, &inline_buf); + if (retval) + goto errout; + + memcpy(inline_buf, (void *)inode.i_block, EXT4_MIN_INLINE_DATA_SIZE); + if (data.ea_size > 0) { + memcpy(inline_buf + EXT4_MIN_INLINE_DATA_SIZE, + data.ea_data, data.ea_size); + } + + memset((void *)inode.i_block, 0, EXT4_MIN_INLINE_DATA_SIZE); + /* + * NOTE: We must do this write -> ea_remove -> read cycle here because + * removing the inline data EA can free the EA block, which is a change + * that our stack copy of the inode will never see. If that happens, + * we can end up with the EA block and lblk 0 pointing to the same + * pblk, which is bad news. + */ + retval = ext2fs_write_inode(fs, ino, &inode); + if (retval) + goto errout; + retval = ext2fs_inline_data_ea_remove(fs, ino); + if (retval) + goto errout; + retval = ext2fs_read_inode(fs, ino, &inode); + if (retval) + goto errout; + + if (LINUX_S_ISDIR(inode.i_mode)) { + retval = ext2fs_inline_data_dir_expand(fs, ino, &inode, + inline_buf, inline_size); + } else { + retval = ext2fs_inline_data_file_expand(fs, ino, &inode, + inline_buf, inline_size); + } + +errout: + if (inline_buf) + ext2fs_free_mem(&inline_buf); + ext2fs_free_mem(&data.ea_data); + return retval; +} + +/* + * When caller uses this function to retrieve the inline data, it must + * allocate a buffer which has the size of inline data. The size of + * inline data can be know by ext2fs_inline_data_get_size(). + */ +errcode_t ext2fs_inline_data_get(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + void *buf, size_t *size) +{ + struct ext2_inode inode_buf; + struct ext2_inline_data data; + errcode_t retval; + + if (!inode) { + retval = ext2fs_read_inode(fs, ino, &inode_buf); + if (retval) + return retval; + inode = &inode_buf; + } + + data.fs = fs; + data.ino = ino; + retval = ext2fs_inline_data_ea_get(&data); + if (retval) + return retval; + + memcpy(buf, (void *)inode->i_block, EXT4_MIN_INLINE_DATA_SIZE); + if (data.ea_size > 0) + memcpy((char *) buf + EXT4_MIN_INLINE_DATA_SIZE, + data.ea_data, data.ea_size); + + if (size) + *size = EXT4_MIN_INLINE_DATA_SIZE + data.ea_size; + ext2fs_free_mem(&data.ea_data); + return 0; +} + +errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + void *buf, size_t size) +{ + struct ext2_inode inode_buf; + struct ext2_inline_data data = { + .fs = fs, + .ino = ino, + }; + errcode_t retval; + size_t free_ea_size, existing_size, free_inode_size; + + if (!inode) { + retval = ext2fs_read_inode(fs, ino, &inode_buf); + if (retval) + return retval; + inode = &inode_buf; + } + + if (size <= EXT4_MIN_INLINE_DATA_SIZE) { + memcpy((void *)inode->i_block, buf, size); + } else { + retval = ext2fs_xattr_inode_max_size(fs, ino, &free_ea_size); + if (retval) + return retval; + + retval = ext2fs_inline_data_size(fs, ino, &existing_size); + if (retval) + return retval; + + if (existing_size < EXT4_MIN_INLINE_DATA_SIZE) { + free_inode_size = EXT4_MIN_INLINE_DATA_SIZE - + existing_size; + } else { + free_inode_size = 0; + } + + if (size != existing_size && + size > existing_size + free_ea_size + free_inode_size) + return EXT2_ET_INLINE_DATA_NO_SPACE; + + memcpy((void *)inode->i_block, buf, EXT4_MIN_INLINE_DATA_SIZE); + if (size > EXT4_MIN_INLINE_DATA_SIZE) + data.ea_size = size - EXT4_MIN_INLINE_DATA_SIZE; + data.ea_data = (char *) buf + EXT4_MIN_INLINE_DATA_SIZE; + } + retval = ext2fs_write_inode(fs, ino, inode); + if (retval) + return retval; + return ext2fs_inline_data_ea_set(&data); +} + +#ifdef DEBUG +#include "e2p/e2p.h" + +/* + * The length of buffer is set to 64 because in inode's i_block member it only + * can save 60 bytes. Thus this value can let the data being saved in extra + * space. + */ +#define BUFF_SIZE (64) + +static errcode_t file_test(ext2_filsys fs) +{ + struct ext2_inode inode; + ext2_ino_t newfile; + errcode_t retval; + size_t size; + char *buf = 0, *cmpbuf = 0; + + /* create a new file */ + retval = ext2fs_new_inode(fs, 2, 010755, 0, &newfile); + if (retval) { + com_err("file_test", retval, "while allocating a new inode"); + return 1; + } + + memset(&inode, 0, sizeof(inode)); + inode.i_flags |= EXT4_INLINE_DATA_FL; + inode.i_size = EXT4_MIN_INLINE_DATA_SIZE; + inode.i_mode = LINUX_S_IFREG; + retval = ext2fs_write_new_inode(fs, newfile, &inode); + if (retval) { + com_err("file_test", retval, "while writing a new inode"); + return 1; + } + + retval = ext2fs_inline_data_init(fs, newfile); + if (retval) { + com_err("file_test", retval, "while init 'system.data'"); + return 1; + } + + retval = ext2fs_inline_data_size(fs, newfile, &size); + if (retval) { + com_err("file_test", retval, "while getting size"); + return 1; + } + + if (size != EXT4_MIN_INLINE_DATA_SIZE) { + fprintf(stderr, + "tst_inline_data: size of inline data is wrong\n"); + return 1; + } + + ext2fs_get_mem(BUFF_SIZE, &buf); + memset(buf, 'a', BUFF_SIZE); + retval = ext2fs_inline_data_set(fs, newfile, 0, buf, BUFF_SIZE); + if (retval) { + com_err("file_test", retval, + "while setting inline data %s", buf); + goto err; + } + + ext2fs_get_mem(BUFF_SIZE, &cmpbuf); + retval = ext2fs_inline_data_get(fs, newfile, 0, cmpbuf, &size); + if (retval) { + com_err("file_test", retval, "while getting inline data"); + goto err; + } + + if (size != BUFF_SIZE) { + fprintf(stderr, + "tst_inline_data: size %lu != buflen %u\n", + size, BUFF_SIZE); + retval = 1; + goto err; + } + + if (memcmp(buf, cmpbuf, BUFF_SIZE)) { + fprintf(stderr, "tst_inline_data: buf != cmpbuf\n"); + retval = 1; + goto err; + } + + retval = ext2fs_punch(fs, newfile, 0, 0, 0, ~0ULL); + if (retval) { + com_err("file_test", retval, "while truncating inode"); + goto err; + } + + /* reload inode and check isize */ + ext2fs_read_inode(fs, newfile, &inode); + if (inode.i_size != 0) { + fprintf(stderr, "tst_inline_data: i_size should be 0\n"); + retval = 1; + } + +err: + if (cmpbuf) + ext2fs_free_mem(&cmpbuf); + if (buf) + ext2fs_free_mem(&buf); + return retval; +} + +static errcode_t dir_test(ext2_filsys fs) +{ + const char *dot_name = "."; + const char *stub_name = "stub"; + const char *parent_name = "test"; + ext2_ino_t parent, dir, tmp; + errcode_t retval; + char dirname[32]; + int i; + + retval = ext2fs_mkdir(fs, 11, 11, stub_name); + if (retval) { + com_err("dir_test", retval, "while creating %s dir", stub_name); + return retval; + } + + retval = ext2fs_mkdir(fs, 11, 0, parent_name); + if (retval) { + com_err("dir_test", retval, + "while creating %s dir", parent_name); + return retval; + } + + retval = ext2fs_lookup(fs, 11, parent_name, strlen(parent_name), + 0, &parent); + if (retval) { + com_err("dir_test", retval, + "while looking up %s dir", parent_name); + return retval; + } + + retval = ext2fs_lookup(fs, parent, dot_name, strlen(dot_name), + 0, &tmp); + if (retval) { + com_err("dir_test", retval, + "while looking up %s dir", parent_name); + return retval; + } + + if (parent != tmp) { + fprintf(stderr, "tst_inline_data: parent (%u) != tmp (%u)\n", + parent, tmp); + return 1; + } + + for (i = 0, dir = 13; i < 4; i++, dir++) { + tmp = 0; + snprintf(dirname, sizeof(dirname), "%d", i); + retval = ext2fs_mkdir(fs, parent, 0, dirname); + if (retval) { + com_err("dir_test", retval, + "while creating %s dir", dirname); + return retval; + } + + retval = ext2fs_lookup(fs, parent, dirname, strlen(dirname), + 0, &tmp); + if (retval) { + com_err("dir_test", retval, + "while looking up %s dir", parent_name); + return retval; + } + + if (dir != tmp) { + fprintf(stderr, + "tst_inline_data: dir (%u) != tmp (%u)\n", + dir, tmp); + return 1; + } + } + + snprintf(dirname, sizeof(dirname), "%d", i); + retval = ext2fs_mkdir(fs, parent, 0, dirname); + if (retval && retval != EXT2_ET_DIR_NO_SPACE) { + com_err("dir_test", retval, "while creating %s dir", dirname); + return retval; + } + + retval = ext2fs_expand_dir(fs, parent); + if (retval) { + com_err("dir_test", retval, "while expanding %s dir", parent_name); + return retval; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + ext2_filsys fs; + struct ext2_super_block param; + errcode_t retval; + + /* setup */ + initialize_ext2_error_table(); + + memset(¶m, 0, sizeof(param)); + ext2fs_blocks_count_set(¶m, 32768); + param.s_inodes_count = 100; + + param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_INLINE_DATA; + param.s_rev_level = EXT2_DYNAMIC_REV; + param.s_inode_size = 256; + + retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, ¶m, + test_io_manager, &fs); + if (retval) { + com_err("setup", retval, + "while initializing filesystem"); + exit(1); + } + + retval = ext2fs_allocate_tables(fs); + if (retval) { + com_err("setup", retval, + "while allocating tables for test filesystem"); + exit(1); + } + + /* initialize inode cache */ + if (!fs->icache) { + ext2_ino_t first_ino = EXT2_FIRST_INO(fs->super); + int i; + + /* we just want to init inode cache. So ignore error */ + ext2fs_create_inode_cache(fs, 16); + if (!fs->icache) { + fprintf(stderr, + "tst_inline_data: init inode cache failed\n"); + exit(1); + } + + /* setup inode cache */ + for (i = 0; i < fs->icache->cache_size; i++) + fs->icache->cache[i].ino = first_ino++; + } + + /* test */ + if (file_test(fs)) { + fprintf(stderr, "tst_inline_data(FILE): FAILED\n"); + return 1; + } + printf("tst_inline_data(FILE): OK\n"); + + if (dir_test(fs)) { + fprintf(stderr, "tst_inline_data(DIR): FAILED\n"); + return 1; + } + printf("tst_inline_data(DIR): OK\n"); + ext2fs_free(fs); + + return 0; +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/inode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/inode.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,1062 @@ +/* + * inode.c --- utility routines to read and write inodes + * + * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" +#include "e2image.h" + +#define IBLOCK_STATUS_CSUMS_OK 1 +#define IBLOCK_STATUS_INSANE 2 +#define SCAN_BLOCK_STATUS(scan) ((scan)->temp_buffer + (scan)->inode_size) + +struct ext2_struct_inode_scan { + errcode_t magic; + ext2_filsys fs; + ext2_ino_t current_inode; + blk64_t current_block; + dgrp_t current_group; + ext2_ino_t inodes_left; + blk_t blocks_left; + dgrp_t groups_left; + blk_t inode_buffer_blocks; + char * inode_buffer; + int inode_size; + char * ptr; + int bytes_left; + char *temp_buffer; + errcode_t (*done_group)(ext2_filsys fs, + ext2_inode_scan scan, + dgrp_t group, + void * priv_data); + void * done_group_data; + int bad_block_ptr; + int scan_flags; + int reserved[6]; +}; + +/* + * This routine flushes the icache, if it exists. + */ +errcode_t ext2fs_flush_icache(ext2_filsys fs) +{ + unsigned i; + + if (!fs->icache) + return 0; + + for (i=0; i < fs->icache->cache_size; i++) + fs->icache->cache[i].ino = 0; + + fs->icache->buffer_blk = 0; + return 0; +} + +/* + * Free the inode cache structure + */ +void ext2fs_free_inode_cache(struct ext2_inode_cache *icache) +{ + unsigned i; + + if (--icache->refcount) + return; + if (icache->buffer) + ext2fs_free_mem(&icache->buffer); + for (i = 0; i < icache->cache_size; i++) + ext2fs_free_mem(&icache->cache[i].inode); + if (icache->cache) + ext2fs_free_mem(&icache->cache); + icache->buffer_blk = 0; + ext2fs_free_mem(&icache); +} + +errcode_t ext2fs_create_inode_cache(ext2_filsys fs, unsigned int cache_size) +{ + unsigned i; + errcode_t retval; + + if (fs->icache) + return 0; + retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), &fs->icache); + if (retval) + return retval; + + memset(fs->icache, 0, sizeof(struct ext2_inode_cache)); + retval = ext2fs_get_mem(fs->blocksize, &fs->icache->buffer); + if (retval) + goto errout; + + fs->icache->buffer_blk = 0; + fs->icache->cache_last = -1; + fs->icache->cache_size = cache_size; + fs->icache->refcount = 1; + retval = ext2fs_get_array(fs->icache->cache_size, + sizeof(struct ext2_inode_cache_ent), + &fs->icache->cache); + if (retval) + goto errout; + + for (i = 0; i < fs->icache->cache_size; i++) { + retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), + &fs->icache->cache[i].inode); + if (retval) + goto errout; + } + + ext2fs_flush_icache(fs); + return 0; +errout: + ext2fs_free_inode_cache(fs->icache); + fs->icache = 0; + return retval; +} + +errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, + ext2_inode_scan *ret_scan) +{ + ext2_inode_scan scan; + errcode_t retval; + errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks); + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + /* + * If fs->badblocks isn't set, then set it --- since the inode + * scanning functions require it. + */ + if (fs->badblocks == 0) { + /* + * Temporarily save fs->get_blocks and set it to zero, + * for compatibility with old e2fsck's. + */ + save_get_blocks = fs->get_blocks; + fs->get_blocks = 0; + retval = ext2fs_read_bb_inode(fs, &fs->badblocks); + if (retval && fs->badblocks) { + ext2fs_badblocks_list_free(fs->badblocks); + fs->badblocks = 0; + } + fs->get_blocks = save_get_blocks; + } + + retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan), &scan); + if (retval) + return retval; + memset(scan, 0, sizeof(struct ext2_struct_inode_scan)); + + scan->magic = EXT2_ET_MAGIC_INODE_SCAN; + scan->fs = fs; + scan->inode_size = EXT2_INODE_SIZE(fs->super); + scan->bytes_left = 0; + scan->current_group = 0; + scan->groups_left = fs->group_desc_count - 1; + scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : + EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS; + scan->current_block = ext2fs_inode_table_loc(scan->fs, + scan->current_group); + scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super); + scan->blocks_left = scan->fs->inode_blocks_per_group; + if (ext2fs_has_group_desc_csum(fs)) { + __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group); + if (scan->inodes_left > unused) + scan->inodes_left -= unused; + else + scan->inodes_left = 0; + scan->blocks_left = + (scan->inodes_left + + (fs->blocksize / scan->inode_size - 1)) * + scan->inode_size / fs->blocksize; + } + retval = io_channel_alloc_buf(fs->io, scan->inode_buffer_blocks, + &scan->inode_buffer); + scan->done_group = 0; + scan->done_group_data = 0; + scan->bad_block_ptr = 0; + if (retval) { + ext2fs_free_mem(&scan); + return retval; + } + retval = ext2fs_get_mem(scan->inode_size + scan->inode_buffer_blocks, + &scan->temp_buffer); + if (retval) { + ext2fs_free_mem(&scan->inode_buffer); + ext2fs_free_mem(&scan); + return retval; + } + memset(SCAN_BLOCK_STATUS(scan), 0, scan->inode_buffer_blocks); + if (scan->fs->badblocks && scan->fs->badblocks->num) + scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS; + if (ext2fs_has_group_desc_csum(fs)) + scan->scan_flags |= EXT2_SF_DO_LAZY; + *ret_scan = scan; + return 0; +} + +void ext2fs_close_inode_scan(ext2_inode_scan scan) +{ + if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) + return; + + ext2fs_free_mem(&scan->inode_buffer); + scan->inode_buffer = NULL; + ext2fs_free_mem(&scan->temp_buffer); + scan->temp_buffer = NULL; + ext2fs_free_mem(&scan); + return; +} + +void ext2fs_set_inode_callback(ext2_inode_scan scan, + errcode_t (*done_group)(ext2_filsys fs, + ext2_inode_scan scan, + dgrp_t group, + void * priv_data), + void *done_group_data) +{ + if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) + return; + + scan->done_group = done_group; + scan->done_group_data = done_group_data; +} + +int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags, + int clear_flags) +{ + int old_flags; + + if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) + return 0; + + old_flags = scan->scan_flags; + scan->scan_flags &= ~clear_flags; + scan->scan_flags |= set_flags; + return old_flags; +} + +/* + * This function is called by ext2fs_get_next_inode when it needs to + * get ready to read in a new blockgroup. + */ +static errcode_t get_next_blockgroup(ext2_inode_scan scan) +{ + ext2_filsys fs = scan->fs; + + scan->current_group++; + scan->groups_left--; + + scan->current_block = ext2fs_inode_table_loc(scan->fs, + scan->current_group); + scan->current_inode = scan->current_group * + EXT2_INODES_PER_GROUP(fs->super); + + scan->bytes_left = 0; + scan->inodes_left = EXT2_INODES_PER_GROUP(fs->super); + scan->blocks_left = fs->inode_blocks_per_group; + if (ext2fs_has_group_desc_csum(fs)) { + __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group); + if (scan->inodes_left > unused) + scan->inodes_left -= unused; + else + scan->inodes_left = 0; + scan->blocks_left = + (scan->inodes_left + + (fs->blocksize / scan->inode_size - 1)) * + scan->inode_size / fs->blocksize; + } + + return 0; +} + +errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan, + int group) +{ + scan->current_group = group - 1; + scan->groups_left = scan->fs->group_desc_count - group; + return get_next_blockgroup(scan); +} + +/* + * This function is called by get_next_blocks() to check for bad + * blocks in the inode table. + * + * This function assumes that badblocks_list->list is sorted in + * increasing order. + */ +static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan, + blk64_t *num_blocks) +{ + blk64_t blk = scan->current_block; + badblocks_list bb = scan->fs->badblocks; + + /* + * If the inode table is missing, then obviously there are no + * bad blocks. :-) + */ + if (blk == 0) + return 0; + + /* + * If the current block is greater than the bad block listed + * in the bad block list, then advance the pointer until this + * is no longer the case. If we run out of bad blocks, then + * we don't need to do any more checking! + */ + while (blk > bb->list[scan->bad_block_ptr]) { + if (++scan->bad_block_ptr >= bb->num) { + scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS; + return 0; + } + } + + /* + * If the current block is equal to the bad block listed in + * the bad block list, then handle that one block specially. + * (We could try to handle runs of bad blocks, but that + * only increases CPU efficiency by a small amount, at the + * expense of a huge expense of code complexity, and for an + * uncommon case at that.) + */ + if (blk == bb->list[scan->bad_block_ptr]) { + scan->scan_flags |= EXT2_SF_BAD_INODE_BLK; + *num_blocks = 1; + if (++scan->bad_block_ptr >= bb->num) + scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS; + return 0; + } + + /* + * If there is a bad block in the range that we're about to + * read in, adjust the number of blocks to read so that we we + * don't read in the bad block. (Then the next block to read + * will be the bad block, which is handled in the above case.) + */ + if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr]) + *num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk); + + return 0; +} + +static int block_map_looks_insane(ext2_filsys fs, + struct ext2_inode_large *inode) +{ + unsigned int i, bad; + + /* We're only interested in block mapped files, dirs, and symlinks */ + if ((inode->i_flags & EXT4_INLINE_DATA_FL) || + (inode->i_flags & EXT4_EXTENTS_FL)) + return 0; + if (!LINUX_S_ISREG(inode->i_mode) && + !LINUX_S_ISLNK(inode->i_mode) && + !LINUX_S_ISDIR(inode->i_mode)) + return 0; + if (LINUX_S_ISLNK(inode->i_mode) && + EXT2_I_SIZE(inode) <= sizeof(inode->i_block)) + return 0; + + /* Unused inodes probably aren't insane */ + if (inode->i_links_count == 0) + return 0; + + /* See if more than half the block maps are insane */ + for (i = 0, bad = 0; i < EXT2_N_BLOCKS; i++) + if (inode->i_block[i] != 0 && + (inode->i_block[i] < fs->super->s_first_data_block || + inode->i_block[i] >= ext2fs_blocks_count(fs->super))) + bad++; + return bad > EXT2_N_BLOCKS / 2; +} + +static int extent_head_looks_insane(struct ext2_inode_large *inode) +{ + if (!(inode->i_flags & EXT4_EXTENTS_FL) || + ext2fs_extent_header_verify(inode->i_block, + sizeof(inode->i_block)) == 0) + return 0; + return 1; +} + +/* + * Check all the inodes that we just read into the buffer. Record what we + * find here -- currently, we can observe that all checksums are ok; more + * than half the inodes are insane; or no conclusions at all. + */ +static void check_inode_block_sanity(ext2_inode_scan scan, blk64_t num_blocks) +{ + ext2_ino_t ino, inodes_to_scan; + unsigned int badness, checksum_failures; + unsigned int inodes_in_buf, inodes_per_block; + char *p; + struct ext2_inode_large *inode; + char *block_status; + unsigned int blk, bad_csum; + + if (!(scan->scan_flags & EXT2_SF_WARN_GARBAGE_INODES)) + return; + + inodes_to_scan = scan->inodes_left; + inodes_in_buf = num_blocks * scan->fs->blocksize / scan->inode_size; + if (inodes_to_scan > inodes_in_buf) + inodes_to_scan = inodes_in_buf; + + p = (char *) scan->inode_buffer; + ino = scan->current_inode + 1; + checksum_failures = badness = 0; + block_status = SCAN_BLOCK_STATUS(scan); + memset(block_status, 0, scan->inode_buffer_blocks); + inodes_per_block = EXT2_INODES_PER_BLOCK(scan->fs->super); + + if (inodes_per_block < 2) + return; + +#ifdef WORDS_BIGENDIAN + if (ext2fs_get_mem(EXT2_INODE_SIZE(scan->fs->super), &inode)) + return; +#endif + + while (inodes_to_scan > 0) { + blk = (p - (char *)scan->inode_buffer) / scan->fs->blocksize; + bad_csum = ext2fs_inode_csum_verify(scan->fs, ino, + (struct ext2_inode_large *) p) == 0; + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_inode_full(scan->fs, + (struct ext2_inode_large *) inode, + (struct ext2_inode_large *) p, + 0, EXT2_INODE_SIZE(scan->fs->super)); +#else + inode = (struct ext2_inode_large *) p; +#endif + + /* Is this inode insane? */ + if (bad_csum) { + checksum_failures++; + badness++; + } else if (extent_head_looks_insane(inode) || + block_map_looks_insane(scan->fs, inode)) + badness++; + + /* If more than half are insane, declare the whole block bad */ + if (badness > inodes_per_block / 2) { + unsigned int ino_adj; + + block_status[blk] |= IBLOCK_STATUS_INSANE; + ino_adj = inodes_per_block - + ((ino - 1) % inodes_per_block); + if (ino_adj > inodes_to_scan) + ino_adj = inodes_to_scan; + inodes_to_scan -= ino_adj; + p += scan->inode_size * ino_adj; + ino += ino_adj; + checksum_failures = badness = 0; + continue; + } + + if ((ino % inodes_per_block) == 0) { + if (checksum_failures == 0) + block_status[blk] |= IBLOCK_STATUS_CSUMS_OK; + checksum_failures = badness = 0; + } + inodes_to_scan--; + p += scan->inode_size; + ino++; + }; + +#ifdef WORDS_BIGENDIAN + ext2fs_free_mem(&inode); +#endif +} + +/* + * This function is called by ext2fs_get_next_inode when it needs to + * read in more blocks from the current blockgroup's inode table. + */ +static errcode_t get_next_blocks(ext2_inode_scan scan) +{ + blk64_t num_blocks; + errcode_t retval; + + /* + * Figure out how many blocks to read; we read at most + * inode_buffer_blocks, and perhaps less if there aren't that + * many blocks left to read. + */ + num_blocks = scan->inode_buffer_blocks; + if (num_blocks > scan->blocks_left) + num_blocks = scan->blocks_left; + + /* + * If the past block "read" was a bad block, then mark the + * left-over extra bytes as also being bad. + */ + if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) { + if (scan->bytes_left) + scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES; + scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK; + } + + /* + * Do inode bad block processing, if necessary. + */ + if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) { + retval = check_for_inode_bad_blocks(scan, &num_blocks); + if (retval) + return retval; + } + + if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) || + (scan->current_block == 0)) { + memset(scan->inode_buffer, 0, + (size_t) num_blocks * scan->fs->blocksize); + } else { + retval = io_channel_read_blk64(scan->fs->io, + scan->current_block, + (int) num_blocks, + scan->inode_buffer); + if (retval) + return EXT2_ET_NEXT_INODE_READ; + } + check_inode_block_sanity(scan, num_blocks); + + scan->ptr = scan->inode_buffer; + scan->bytes_left = num_blocks * scan->fs->blocksize; + + scan->blocks_left -= num_blocks; + if (scan->current_block) + scan->current_block += num_blocks; + + return 0; +} + +#if 0 +/* + * Returns 1 if the entire inode_buffer has a non-zero size and + * contains all zeros. (Not just deleted inodes, since that means + * that part of the inode table was used at one point; we want all + * zeros, which means that the inode table is pristine.) + */ +static inline int is_empty_scan(ext2_inode_scan scan) +{ + int i; + + if (scan->bytes_left == 0) + return 0; + + for (i=0; i < scan->bytes_left; i++) + if (scan->ptr[i]) + return 0; + return 1; +} +#endif + +errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino, + struct ext2_inode *inode, int bufsize) +{ + errcode_t retval; + int extra_bytes = 0; + int length; + struct ext2_inode_large *iptr = (struct ext2_inode_large *)inode; + char *iblock_status; + unsigned int iblk; + + EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN); + length = EXT2_INODE_SIZE(scan->fs->super); + iblock_status = SCAN_BLOCK_STATUS(scan); + + /* + * Do we need to start reading a new block group? + */ + if (scan->inodes_left <= 0) { + force_new_group: + if (scan->done_group) { + retval = (scan->done_group) + (scan->fs, scan, scan->current_group, + scan->done_group_data); + if (retval) + return retval; + } + if (scan->groups_left <= 0) { + *ino = 0; + return 0; + } + retval = get_next_blockgroup(scan); + if (retval) + return retval; + } + /* + * These checks are done outside the above if statement so + * they can be done for block group #0. + */ + if ((scan->scan_flags & EXT2_SF_DO_LAZY) && + (ext2fs_bg_flags_test(scan->fs, scan->current_group, EXT2_BG_INODE_UNINIT) + )) + goto force_new_group; + if (scan->inodes_left == 0) + goto force_new_group; + if (scan->current_block == 0) { + if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) { + goto force_new_group; + } else + return EXT2_ET_MISSING_INODE_TABLE; + } + + + /* + * Have we run out of space in the inode buffer? If so, we + * need to read in more blocks. + */ + if (scan->bytes_left < scan->inode_size) { + if (scan->bytes_left) + memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left); + extra_bytes = scan->bytes_left; + + retval = get_next_blocks(scan); + if (retval) + return retval; +#if 0 + /* + * XXX test Need check for used inode somehow. + * (Note: this is hard.) + */ + if (is_empty_scan(scan)) + goto force_new_group; +#endif + } + + if (bufsize < length) { + retval = ext2fs_get_mem(length, &iptr); + if (retval) + return retval; + } + + retval = 0; + iblk = scan->current_inode % EXT2_INODES_PER_GROUP(scan->fs->super) / + EXT2_INODES_PER_BLOCK(scan->fs->super) % + scan->inode_buffer_blocks; + if (extra_bytes) { + memcpy(scan->temp_buffer+extra_bytes, scan->ptr, + scan->inode_size - extra_bytes); + scan->ptr += scan->inode_size - extra_bytes; + scan->bytes_left -= scan->inode_size - extra_bytes; + + /* Verify the inode checksum. */ + if (!(iblock_status[iblk] & IBLOCK_STATUS_CSUMS_OK) && + !(scan->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_inode_csum_verify(scan->fs, scan->current_inode + 1, + (struct ext2_inode_large *)scan->temp_buffer)) + retval = EXT2_ET_INODE_CSUM_INVALID; + +#ifdef WORDS_BIGENDIAN + memset(iptr, 0, length); + ext2fs_swap_inode_full(scan->fs, + (struct ext2_inode_large *) iptr, + (struct ext2_inode_large *) scan->temp_buffer, + 0, length); +#else + memcpy(iptr, scan->temp_buffer, length); +#endif + if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES) + retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE; + scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES; + } else { + /* Verify the inode checksum. */ + if (!(iblock_status[iblk] & IBLOCK_STATUS_CSUMS_OK) && + !(scan->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_inode_csum_verify(scan->fs, scan->current_inode + 1, + (struct ext2_inode_large *)scan->ptr)) + retval = EXT2_ET_INODE_CSUM_INVALID; + +#ifdef WORDS_BIGENDIAN + memset(iptr, 0, length); + ext2fs_swap_inode_full(scan->fs, + (struct ext2_inode_large *) iptr, + (struct ext2_inode_large *) scan->ptr, + 0, length); +#else + memcpy(iptr, scan->ptr, length); +#endif + scan->ptr += scan->inode_size; + scan->bytes_left -= scan->inode_size; + if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) + retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE; + } + if ((iblock_status[iblk] & IBLOCK_STATUS_INSANE) && + (retval == 0 || retval == EXT2_ET_INODE_CSUM_INVALID)) + retval = EXT2_ET_INODE_IS_GARBAGE; + + scan->inodes_left--; + scan->current_inode++; + *ino = scan->current_inode; + if (iptr != (struct ext2_inode_large *)inode) { + memcpy(inode, iptr, bufsize); + ext2fs_free_mem(&iptr); + } + return retval; +} + +errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino, + struct ext2_inode *inode) +{ + return ext2fs_get_next_inode_full(scan, ino, inode, + sizeof(struct ext2_inode)); +} + +/* + * Functions to read and write a single inode. + */ +errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode, int bufsize) +{ + blk64_t block_nr; + unsigned long group, block, offset; + char *ptr; + errcode_t retval; + unsigned i; + int clen, inodes_per_block; + io_channel io; + int length = EXT2_INODE_SIZE(fs->super); + struct ext2_inode_large *iptr; + int cache_slot, fail_csum; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + /* Check to see if user has an override function */ + if (fs->read_inode && + ((bufsize == sizeof(struct ext2_inode)) || + (EXT2_INODE_SIZE(fs->super) == sizeof(struct ext2_inode)))) { + retval = (fs->read_inode)(fs, ino, inode); + if (retval != EXT2_ET_CALLBACK_NOTHANDLED) + return retval; + } + if ((ino == 0) || (ino > fs->super->s_inodes_count)) + return EXT2_ET_BAD_INODE_NUM; + /* Create inode cache if not present */ + if (!fs->icache) { + retval = ext2fs_create_inode_cache(fs, 4); + if (retval) + return retval; + } + /* Check to see if it's in the inode cache */ + for (i = 0; i < fs->icache->cache_size; i++) { + if (fs->icache->cache[i].ino == ino) { + memcpy(inode, fs->icache->cache[i].inode, + (bufsize > length) ? length : bufsize); + return 0; + } + } + if (fs->flags & EXT2_FLAG_IMAGE_FILE) { + inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super); + block_nr = ext2fs_le32_to_cpu(fs->image_header->offset_inode) / fs->blocksize; + block_nr += (ino - 1) / inodes_per_block; + offset = ((ino - 1) % inodes_per_block) * + EXT2_INODE_SIZE(fs->super); + io = fs->image_io; + } else { + group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super); + if (group > fs->group_desc_count) + return EXT2_ET_BAD_INODE_NUM; + offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) * + EXT2_INODE_SIZE(fs->super); + block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super); + if (!ext2fs_inode_table_loc(fs, (unsigned) group)) + return EXT2_ET_MISSING_INODE_TABLE; + block_nr = ext2fs_inode_table_loc(fs, group) + + block; + io = fs->io; + } + offset &= (EXT2_BLOCK_SIZE(fs->super) - 1); + + cache_slot = (fs->icache->cache_last + 1) % fs->icache->cache_size; + iptr = (struct ext2_inode_large *)fs->icache->cache[cache_slot].inode; + + ptr = (char *) iptr; + while (length) { + clen = length; + if ((offset + length) > fs->blocksize) + clen = fs->blocksize - offset; + + if (block_nr != fs->icache->buffer_blk) { + retval = io_channel_read_blk64(io, block_nr, 1, + fs->icache->buffer); + if (retval) + return retval; + fs->icache->buffer_blk = block_nr; + } + + memcpy(ptr, ((char *) fs->icache->buffer) + (unsigned) offset, + clen); + + offset = 0; + length -= clen; + ptr += clen; + block_nr++; + } + length = EXT2_INODE_SIZE(fs->super); + + /* Verify the inode checksum. */ + fail_csum = !ext2fs_inode_csum_verify(fs, ino, iptr); + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) iptr, + (struct ext2_inode_large *) iptr, + 0, length); +#endif + + /* Update the inode cache bookkeeping */ + if (!fail_csum) { + fs->icache->cache_last = cache_slot; + fs->icache->cache[cache_slot].ino = ino; + } + memcpy(inode, iptr, (bufsize > length) ? length : bufsize); + + if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && fail_csum) + return EXT2_ET_INODE_CSUM_INVALID; + + return 0; +} + +errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode) +{ + return ext2fs_read_inode_full(fs, ino, inode, + sizeof(struct ext2_inode)); +} + +errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode, int bufsize) +{ + blk64_t block_nr; + unsigned long group, block, offset; + errcode_t retval = 0; + struct ext2_inode_large *w_inode; + char *ptr; + unsigned i; + int clen; + int length = EXT2_INODE_SIZE(fs->super); + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + /* Check to see if user provided an override function */ + if (fs->write_inode) { + retval = (fs->write_inode)(fs, ino, inode); + if (retval != EXT2_ET_CALLBACK_NOTHANDLED) + return retval; + } + + if ((ino == 0) || (ino > fs->super->s_inodes_count)) + return EXT2_ET_BAD_INODE_NUM; + + /* Prepare our shadow buffer for read/modify/byteswap/write */ + retval = ext2fs_get_mem(length, &w_inode); + if (retval) + return retval; + + if (bufsize < length) { + int old_flags = fs->flags; + fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; + retval = ext2fs_read_inode_full(fs, ino, + (struct ext2_inode *)w_inode, + length); + fs->flags = (old_flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) | + (fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS); + if (retval) + goto errout; + } + + /* Check to see if the inode cache needs to be updated */ + if (fs->icache) { + for (i=0; i < fs->icache->cache_size; i++) { + if (fs->icache->cache[i].ino == ino) { + memcpy(fs->icache->cache[i].inode, inode, + (bufsize > length) ? length : bufsize); + break; + } + } + } else { + retval = ext2fs_create_inode_cache(fs, 4); + if (retval) + goto errout; + } + memcpy(w_inode, inode, (bufsize > length) ? length : bufsize); + + if (!(fs->flags & EXT2_FLAG_RW)) { + retval = EXT2_ET_RO_FILSYS; + goto errout; + } + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_inode_full(fs, w_inode, w_inode, 1, length); +#endif + + retval = ext2fs_inode_csum_set(fs, ino, w_inode); + if (retval) + goto errout; + + group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super); + offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) * + EXT2_INODE_SIZE(fs->super); + block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super); + if (!ext2fs_inode_table_loc(fs, (unsigned) group)) { + retval = EXT2_ET_MISSING_INODE_TABLE; + goto errout; + } + block_nr = ext2fs_inode_table_loc(fs, (unsigned) group) + block; + + offset &= (EXT2_BLOCK_SIZE(fs->super) - 1); + + ptr = (char *) w_inode; + + while (length) { + clen = length; + if ((offset + length) > fs->blocksize) + clen = fs->blocksize - offset; + + if (fs->icache->buffer_blk != block_nr) { + retval = io_channel_read_blk64(fs->io, block_nr, 1, + fs->icache->buffer); + if (retval) + goto errout; + fs->icache->buffer_blk = block_nr; + } + + + memcpy((char *) fs->icache->buffer + (unsigned) offset, + ptr, clen); + + retval = io_channel_write_blk64(fs->io, block_nr, 1, + fs->icache->buffer); + if (retval) + goto errout; + + offset = 0; + ptr += clen; + length -= clen; + block_nr++; + } + + fs->flags |= EXT2_FLAG_CHANGED; +errout: + ext2fs_free_mem(&w_inode); + return retval; +} + +errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode) +{ + return ext2fs_write_inode_full(fs, ino, inode, + sizeof(struct ext2_inode)); +} + +/* + * This function should be called when writing a new inode. It makes + * sure that extra part of large inodes is initialized properly. + */ +errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode) +{ + struct ext2_inode *buf; + int size = EXT2_INODE_SIZE(fs->super); + struct ext2_inode_large *large_inode; + errcode_t retval; + __u32 t = fs->now ? fs->now : time(NULL); + + if (!inode->i_ctime) + inode->i_ctime = t; + if (!inode->i_mtime) + inode->i_mtime = t; + if (!inode->i_atime) + inode->i_atime = t; + + if (size == sizeof(struct ext2_inode)) + return ext2fs_write_inode_full(fs, ino, inode, + sizeof(struct ext2_inode)); + + buf = malloc(size); + if (!buf) + return ENOMEM; + + memset(buf, 0, size); + *buf = *inode; + + large_inode = (struct ext2_inode_large *) buf; + large_inode->i_extra_isize = sizeof(struct ext2_inode_large) - + EXT2_GOOD_OLD_INODE_SIZE; + if (!large_inode->i_crtime) + large_inode->i_crtime = t; + + retval = ext2fs_write_inode_full(fs, ino, buf, size); + free(buf); + return retval; +} + + +errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks) +{ + struct ext2_inode inode; + int i; + errcode_t retval; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (ino > fs->super->s_inodes_count) + return EXT2_ET_BAD_INODE_NUM; + + if (fs->get_blocks) { + if (!(*fs->get_blocks)(fs, ino, blocks)) + return 0; + } + retval = ext2fs_read_inode(fs, ino, &inode); + if (retval) + return retval; + for (i=0; i < EXT2_N_BLOCKS; i++) + blocks[i] = inode.i_block[i]; + return 0; +} + +errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_inode inode; + errcode_t retval; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (ino > fs->super->s_inodes_count) + return EXT2_ET_BAD_INODE_NUM; + + if (fs->check_directory) { + retval = (fs->check_directory)(fs, ino); + if (retval != EXT2_ET_CALLBACK_NOTHANDLED) + return retval; + } + retval = ext2fs_read_inode(fs, ino, &inode); + if (retval) + return retval; + if (!LINUX_S_ISDIR(inode.i_mode)) + return EXT2_ET_NO_DIRECTORY; + return 0; +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/inode_io.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/inode_io.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,290 @@ +/* + * inode_io.c --- This is allows an inode in an ext2 filesystem image + * to be accessed via the I/O manager interface. + * + * Copyright (C) 2002 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include + +#include "ext2_fs.h" +#include "ext2fs.h" + +/* + * For checking structure magic numbers... + */ + +#define EXT2_CHECK_MAGIC(struct, code) \ + if ((struct)->magic != (code)) return (code) + +struct inode_private_data { + int magic; + char name[32]; + ext2_file_t file; + ext2_filsys fs; + ext2_ino_t ino; + struct ext2_inode inode; + int flags; + struct inode_private_data *next; +}; + +#define CHANNEL_HAS_INODE 0x8000 + +static struct inode_private_data *top_intern; +static int ino_unique = 0; + +static errcode_t inode_open(const char *name, int flags, io_channel *channel); +static errcode_t inode_close(io_channel channel); +static errcode_t inode_set_blksize(io_channel channel, int blksize); +static errcode_t inode_read_blk(io_channel channel, unsigned long block, + int count, void *data); +static errcode_t inode_write_blk(io_channel channel, unsigned long block, + int count, const void *data); +static errcode_t inode_flush(io_channel channel); +static errcode_t inode_write_byte(io_channel channel, unsigned long offset, + int size, const void *data); +static errcode_t inode_read_blk64(io_channel channel, + unsigned long long block, int count, void *data); +static errcode_t inode_write_blk64(io_channel channel, + unsigned long long block, int count, const void *data); + +static struct struct_io_manager struct_inode_manager = { + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name = "Inode I/O Manager", + .open = inode_open, + .close = inode_close, + .set_blksize = inode_set_blksize, + .read_blk = inode_read_blk, + .write_blk = inode_write_blk, + .flush = inode_flush, + .write_byte = inode_write_byte, + .read_blk64 = inode_read_blk64, + .write_blk64 = inode_write_blk64 +}; + +io_manager inode_io_manager = &struct_inode_manager; + +errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + char **name) +{ + struct inode_private_data *data; + errcode_t retval; + + if ((retval = ext2fs_get_mem(sizeof(struct inode_private_data), + &data))) + return retval; + data->magic = EXT2_ET_MAGIC_INODE_IO_CHANNEL; + sprintf(data->name, "%u:%d", ino, ino_unique++); + data->file = 0; + data->fs = fs; + data->ino = ino; + data->flags = 0; + if (inode) { + memcpy(&data->inode, inode, sizeof(struct ext2_inode)); + data->flags |= CHANNEL_HAS_INODE; + } + data->next = top_intern; + top_intern = data; + *name = data->name; + return 0; +} + +errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino, + char **name) +{ + return ext2fs_inode_io_intern2(fs, ino, NULL, name); +} + + +static errcode_t inode_open(const char *name, int flags, io_channel *channel) +{ + io_channel io = NULL; + struct inode_private_data *prev, *data = NULL; + errcode_t retval; + int open_flags; + + if (name == 0) + return EXT2_ET_BAD_DEVICE_NAME; + + for (data = top_intern, prev = NULL; data; + prev = data, data = data->next) + if (strcmp(name, data->name) == 0) + break; + if (!data) + return ENOENT; + if (prev) + prev->next = data->next; + else + top_intern = data->next; + + retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io); + if (retval) + goto cleanup; + memset(io, 0, sizeof(struct struct_io_channel)); + + io->magic = EXT2_ET_MAGIC_IO_CHANNEL; + io->manager = inode_io_manager; + retval = ext2fs_get_mem(strlen(name)+1, &io->name); + if (retval) + goto cleanup; + + strcpy(io->name, name); + io->private_data = data; + io->block_size = 1024; + io->read_error = 0; + io->write_error = 0; + io->refcount = 1; + + open_flags = (flags & IO_FLAG_RW) ? EXT2_FILE_WRITE : 0; + retval = ext2fs_file_open2(data->fs, data->ino, + (data->flags & CHANNEL_HAS_INODE) ? + &data->inode : 0, open_flags, + &data->file); + if (retval) + goto cleanup; + + *channel = io; + return 0; + +cleanup: + if (io && io->name) + ext2fs_free_mem(&io->name); + if (data) + ext2fs_free_mem(&data); + if (io) + ext2fs_free_mem(&io); + return retval; +} + +static errcode_t inode_close(io_channel channel) +{ + struct inode_private_data *data; + errcode_t retval = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct inode_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); + + if (--channel->refcount > 0) + return 0; + + retval = ext2fs_file_close(data->file); + + ext2fs_free_mem(&channel->private_data); + if (channel->name) + ext2fs_free_mem(&channel->name); + ext2fs_free_mem(&channel); + return retval; +} + +static errcode_t inode_set_blksize(io_channel channel, int blksize) +{ + struct inode_private_data *data; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct inode_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); + + channel->block_size = blksize; + return 0; +} + + +static errcode_t inode_read_blk64(io_channel channel, + unsigned long long block, int count, void *buf) +{ + struct inode_private_data *data; + errcode_t retval; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct inode_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); + + if ((retval = ext2fs_file_lseek(data->file, + block * channel->block_size, + EXT2_SEEK_SET, 0))) + return retval; + + count = (count < 0) ? -count : (count * channel->block_size); + + return ext2fs_file_read(data->file, buf, count, 0); +} + +static errcode_t inode_read_blk(io_channel channel, unsigned long block, + int count, void *buf) +{ + return inode_read_blk64(channel, block, count, buf); +} + +static errcode_t inode_write_blk64(io_channel channel, + unsigned long long block, int count, const void *buf) +{ + struct inode_private_data *data; + errcode_t retval; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct inode_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); + + if ((retval = ext2fs_file_lseek(data->file, + block * channel->block_size, + EXT2_SEEK_SET, 0))) + return retval; + + count = (count < 0) ? -count : (count * channel->block_size); + + return ext2fs_file_write(data->file, buf, count, 0); +} + +static errcode_t inode_write_blk(io_channel channel, unsigned long block, + int count, const void *buf) +{ + return inode_write_blk64(channel, block, count, buf); +} + +static errcode_t inode_write_byte(io_channel channel, unsigned long offset, + int size, const void *buf) +{ + struct inode_private_data *data; + errcode_t retval = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct inode_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); + + if ((retval = ext2fs_file_lseek(data->file, offset, + EXT2_SEEK_SET, 0))) + return retval; + + return ext2fs_file_write(data->file, buf, size, 0); +} + +/* + * Flush data buffers to disk. + */ +static errcode_t inode_flush(io_channel channel) +{ + struct inode_private_data *data; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct inode_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); + + return ext2fs_file_flush(data->file); +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/io_manager.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/io_manager.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,150 @@ +/* + * io_manager.c --- the I/O manager abstraction + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +errcode_t io_channel_set_options(io_channel channel, const char *opts) +{ + errcode_t retval = 0; + char *next, *ptr, *options, *arg; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + + if (!opts) + return 0; + + if (!channel->manager->set_option) + return EXT2_ET_INVALID_ARGUMENT; + + options = malloc(strlen(opts)+1); + if (!options) + return EXT2_ET_NO_MEMORY; + strcpy(options, opts); + ptr = options; + + while (ptr && *ptr) { + next = strchr(ptr, '&'); + if (next) + *next++ = 0; + + arg = strchr(ptr, '='); + if (arg) + *arg++ = 0; + + retval = (channel->manager->set_option)(channel, ptr, arg); + if (retval) + break; + ptr = next; + } + free(options); + return retval; +} + +errcode_t io_channel_write_byte(io_channel channel, unsigned long offset, + int count, const void *data) +{ + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + + if (channel->manager->write_byte) + return channel->manager->write_byte(channel, offset, + count, data); + + return EXT2_ET_UNIMPLEMENTED; +} + +errcode_t io_channel_read_blk64(io_channel channel, unsigned long long block, + int count, void *data) +{ + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + + if (channel->manager->read_blk64) + return (channel->manager->read_blk64)(channel, block, + count, data); + + if ((block >> 32) != 0) + return EXT2_ET_IO_CHANNEL_NO_SUPPORT_64; + + return (channel->manager->read_blk)(channel, (unsigned long) block, + count, data); +} + +errcode_t io_channel_write_blk64(io_channel channel, unsigned long long block, + int count, const void *data) +{ + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + + if (channel->manager->write_blk64) + return (channel->manager->write_blk64)(channel, block, + count, data); + + if ((block >> 32) != 0) + return EXT2_ET_IO_CHANNEL_NO_SUPPORT_64; + + return (channel->manager->write_blk)(channel, (unsigned long) block, + count, data); +} + +errcode_t io_channel_discard(io_channel channel, unsigned long long block, + unsigned long long count) +{ + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + + if (channel->manager->discard) + return (channel->manager->discard)(channel, block, count); + + return EXT2_ET_UNIMPLEMENTED; +} + +errcode_t io_channel_zeroout(io_channel channel, unsigned long long block, + unsigned long long count) +{ + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + + if (channel->manager->zeroout) + return (channel->manager->zeroout)(channel, block, count); + + return EXT2_ET_UNIMPLEMENTED; +} + +errcode_t io_channel_alloc_buf(io_channel io, int count, void *ptr) +{ + size_t size; + + if (count == 0) + size = io->block_size; + else if (count > 0) + size = io->block_size * count; + else + size = -count; + + if (io->align) + return ext2fs_get_memalign(size, io->align, ptr); + else + return ext2fs_get_mem(size, ptr); +} + +errcode_t io_channel_cache_readahead(io_channel io, unsigned long long block, + unsigned long long count) +{ + if (!io->manager->cache_readahead) + return EXT2_ET_OP_NOT_SUPPORTED; + + return io->manager->cache_readahead(io, block, count); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/irel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/irel.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,114 @@ +/* + * irel.h + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +struct ext2_inode_reference { + blk64_t block; + __u16 offset; +}; + +struct ext2_inode_relocate_entry { + ext2_ino_t new; + ext2_ino_t orig; + __u16 flags; + __u16 max_refs; +}; + +typedef struct ext2_inode_relocation_table *ext2_irel; + +struct ext2_inode_relocation_table { + __u32 magic; + char *name; + ext2_ino_t current; + void *priv_data; + + /* + * Add an inode relocation entry. + */ + errcode_t (*put)(ext2_irel irel, ext2_ino_t old, + struct ext2_inode_relocate_entry *ent); + /* + * Get an inode relocation entry. + */ + errcode_t (*get)(ext2_irel irel, ext2_ino_t old, + struct ext2_inode_relocate_entry *ent); + + /* + * Get an inode relocation entry by its original inode number + */ + errcode_t (*get_by_orig)(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old, + struct ext2_inode_relocate_entry *ent); + + /* + * Initialize for iterating over the inode relocation entries. + */ + errcode_t (*start_iter)(ext2_irel irel); + + /* + * The iterator function for the inode relocation entries. + * Returns an inode number of 0 when out of entries. + */ + errcode_t (*next)(ext2_irel irel, ext2_ino_t *old, + struct ext2_inode_relocate_entry *ent); + + /* + * Add an inode reference (i.e., note the fact that a + * particular block/offset contains a reference to an inode) + */ + errcode_t (*add_ref)(ext2_irel irel, ext2_ino_t ino, + struct ext2_inode_reference *ref); + + /* + * Initialize for iterating over the inode references for a + * particular inode. + */ + errcode_t (*start_iter_ref)(ext2_irel irel, ext2_ino_t ino); + + /* + * The iterator function for the inode references for an + * inode. The references for only one inode can be interator + * over at a time, as the iterator state is stored in ext2_irel. + */ + errcode_t (*next_ref)(ext2_irel irel, + struct ext2_inode_reference *ref); + + /* + * Move the inode relocation table from one inode number to + * another. Note that the inode references also must move. + */ + errcode_t (*move)(ext2_irel irel, ext2_ino_t old, ext2_ino_t new); + + /* + * Remove an inode relocation entry, along with all of the + * inode references. + */ + errcode_t (*delete)(ext2_irel irel, ext2_ino_t old); + + /* + * Free the inode relocation table. + */ + errcode_t (*free)(ext2_irel irel); +}; + +errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode, + ext2_irel *irel); + +#define ext2fs_irel_put(irel, old, ent) ((irel)->put((irel), old, ent)) +#define ext2fs_irel_get(irel, old, ent) ((irel)->get((irel), old, ent)) +#define ext2fs_irel_get_by_orig(irel, orig, old, ent) \ + ((irel)->get_by_orig((irel), orig, old, ent)) +#define ext2fs_irel_start_iter(irel) ((irel)->start_iter((irel))) +#define ext2fs_irel_next(irel, old, ent) ((irel)->next((irel), old, ent)) +#define ext2fs_irel_add_ref(irel, ino, ref) ((irel)->add_ref((irel), ino, ref)) +#define ext2fs_irel_start_iter_ref(irel, ino) ((irel)->start_iter_ref((irel), ino)) +#define ext2fs_irel_next_ref(irel, ref) ((irel)->next_ref((irel), ref)) +#define ext2fs_irel_move(irel, old, new) ((irel)->move((irel), old, new)) +#define ext2fs_irel_delete(irel, old) ((irel)->delete((irel), old)) +#define ext2fs_irel_free(irel) ((irel)->free((irel))) diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/ismounted.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/ismounted.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,468 @@ +/* + * ismounted.c --- Check to see if the filesystem was mounted + * + * Copyright (C) 1995,1996,1997,1998,1999,2000 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +/* define BSD_SOURCE to make sure we get the major() macro */ +#ifndef _BSD_SOURCE +#define _BSD_SOURCE +#endif +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE /* since glibc 2.20 _SVID_SOURCE is deprecated */ +#endif + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_LINUX_FD_H +#include +#endif +#ifdef HAVE_LINUX_LOOP_H +#include +#include +#ifdef HAVE_LINUX_MAJOR_H +#include +#endif /* HAVE_LINUX_MAJOR_H */ +#endif /* HAVE_LINUX_LOOP_H */ +#ifdef HAVE_MNTENT_H +#include +#endif +#ifdef HAVE_GETMNTINFO +#include +#include +#include +#endif /* HAVE_GETMNTINFO */ +#include +#include +#if HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SYSMACROS_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +#ifdef HAVE_SETMNTENT +/* + * Check to see if a regular file is mounted. + * If /etc/mtab/ is a symlink of /proc/mounts, you will need the following check + * because the name in /proc/mounts is a loopback device not a regular file. + */ +static int check_loop_mounted(const char *mnt_fsname, dev_t mnt_rdev, + dev_t file_dev, ino_t file_ino) +{ +#if defined(HAVE_LINUX_LOOP_H) && defined(HAVE_LINUX_MAJOR_H) + struct loop_info64 loopinfo = {0, }; + int loop_fd, ret; + + if (major(mnt_rdev) == LOOP_MAJOR) { + loop_fd = open(mnt_fsname, O_RDONLY); + if (loop_fd < 0) + return -1; + + ret = ioctl(loop_fd, LOOP_GET_STATUS64, &loopinfo); + close(loop_fd); + if (ret < 0) + return -1; + + if (file_dev == loopinfo.lo_device && + file_ino == loopinfo.lo_inode) + return 1; + } +#endif /* defined(HAVE_LINUX_LOOP_H) && defined(HAVE_LINUX_MAJOR_H) */ + return 0; +} + +/* + * Helper function which checks a file in /etc/mtab format to see if a + * filesystem is mounted. Returns an error if the file doesn't exist + * or can't be opened. + */ +static errcode_t check_mntent_file(const char *mtab_file, const char *file, + int *mount_flags, char *mtpt, int mtlen) +{ + struct mntent *mnt; + struct stat st_buf; + errcode_t retval = 0; + dev_t file_dev=0, file_rdev=0; + ino_t file_ino=0; + FILE *f; + int fd; + + *mount_flags = 0; + + if ((f = setmntent (mtab_file, "r")) == NULL) { + if (errno == ENOENT) { + if (getenv("EXT2FS_NO_MTAB_OK")) + return 0; + else + return EXT2_ET_NO_MTAB_FILE; + } + return errno; + } + if (stat(file, &st_buf) == 0) { + if (ext2fsP_is_disk_device(st_buf.st_mode)) { +#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ + file_rdev = st_buf.st_rdev; +#endif /* __GNU__ */ + } else { + file_dev = st_buf.st_dev; + file_ino = st_buf.st_ino; + } + } + while ((mnt = getmntent (f)) != NULL) { + if (mnt->mnt_fsname[0] != '/') + continue; + if (strcmp(file, mnt->mnt_fsname) == 0) + break; + if (stat(mnt->mnt_fsname, &st_buf) == 0) { + if (ext2fsP_is_disk_device(st_buf.st_mode)) { +#ifndef __GNU__ + if (file_rdev && (file_rdev == st_buf.st_rdev)) + break; + if (check_loop_mounted(mnt->mnt_fsname, + st_buf.st_rdev, file_dev, + file_ino) == 1) + break; +#endif /* __GNU__ */ + } else { + if (file_dev && ((file_dev == st_buf.st_dev) && + (file_ino == st_buf.st_ino))) + break; + } + } + } + + if (mnt == 0) { +#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ + /* + * Do an extra check to see if this is the root device. We + * can't trust /etc/mtab, and /proc/mounts will only list + * /dev/root for the root filesystem. Argh. Instead we + * check if the given device has the same major/minor number + * as the device that the root directory is on. + */ + if (file_rdev && stat("/", &st_buf) == 0) { + if (st_buf.st_dev == file_rdev) { + *mount_flags = EXT2_MF_MOUNTED; + if (mtpt) + strncpy(mtpt, "/", mtlen); + goto is_root; + } + } +#endif /* __GNU__ */ + goto errout; + } +#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */ + /* Validate the entry in case /etc/mtab is out of date */ + /* + * We need to be paranoid, because some broken distributions + * (read: Slackware) don't initialize /etc/mtab before checking + * all of the non-root filesystems on the disk. + */ + if (stat(mnt->mnt_dir, &st_buf) < 0) { + retval = errno; + if (retval == ENOENT) { +#ifdef DEBUG + printf("Bogus entry in %s! (%s does not exist)\n", + mtab_file, mnt->mnt_dir); +#endif /* DEBUG */ + retval = 0; + } + goto errout; + } + if (file_rdev && (st_buf.st_dev != file_rdev)) { +#ifdef DEBUG + printf("Bogus entry in %s! (%s not mounted on %s)\n", + mtab_file, file, mnt->mnt_dir); +#endif /* DEBUG */ + goto errout; + } +#endif /* __GNU__ */ + *mount_flags = EXT2_MF_MOUNTED; + +#ifdef MNTOPT_RO + /* Check to see if the ro option is set */ + if (hasmntopt(mnt, MNTOPT_RO)) + *mount_flags |= EXT2_MF_READONLY; +#endif + + if (mtpt) + strncpy(mtpt, mnt->mnt_dir, mtlen); + /* + * Check to see if we're referring to the root filesystem. + * If so, do a manual check to see if we can open /etc/mtab + * read/write, since if the root is mounted read/only, the + * contents of /etc/mtab may not be accurate. + */ + if (!strcmp(mnt->mnt_dir, "/")) { +is_root: +#define TEST_FILE "/.ismount-test-file" + *mount_flags |= EXT2_MF_ISROOT; + fd = open(TEST_FILE, O_RDWR|O_CREAT, 0600); + if (fd < 0) { + if (errno == EROFS) + *mount_flags |= EXT2_MF_READONLY; + } else + close(fd); + (void) unlink(TEST_FILE); + } + retval = 0; +errout: + endmntent (f); + return retval; +} + +static errcode_t check_mntent(const char *file, int *mount_flags, + char *mtpt, int mtlen) +{ + errcode_t retval; + +#ifdef DEBUG + retval = check_mntent_file("/tmp/mtab", file, mount_flags, + mtpt, mtlen); + if (retval == 0) + return 0; +#endif /* DEBUG */ +#ifdef __linux__ + retval = check_mntent_file("/proc/mounts", file, mount_flags, + mtpt, mtlen); + if (retval == 0 && (*mount_flags != 0)) + return 0; +#endif /* __linux__ */ +#if defined(MOUNTED) || defined(_PATH_MOUNTED) +#ifndef MOUNTED +#define MOUNTED _PATH_MOUNTED +#endif /* MOUNTED */ + retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen); + return retval; +#else + *mount_flags = 0; + return 0; +#endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */ +} + +#else +#if defined(HAVE_GETMNTINFO) + +static errcode_t check_getmntinfo(const char *file, int *mount_flags, + char *mtpt, int mtlen) +{ + struct statfs *mp; + int len, n; + const char *s1; + char *s2; + + n = getmntinfo(&mp, MNT_NOWAIT); + if (n == 0) + return errno; + + len = sizeof(_PATH_DEV) - 1; + s1 = file; + if (strncmp(_PATH_DEV, s1, len) == 0) + s1 += len; + + *mount_flags = 0; + while (--n >= 0) { + s2 = mp->f_mntfromname; + if (strncmp(_PATH_DEV, s2, len) == 0) { + s2 += len - 1; + *s2 = 'r'; + } + if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) { + *mount_flags = EXT2_MF_MOUNTED; + break; + } + ++mp; + } + if (mtpt) + strncpy(mtpt, mp->f_mntonname, mtlen); + return 0; +} +#endif /* HAVE_GETMNTINFO */ +#endif /* HAVE_SETMNTENT */ + +/* + * Check to see if we're dealing with the swap device. + */ +static int is_swap_device(const char *file) +{ + FILE *f; + char buf[1024], *cp; + dev_t file_dev; + struct stat st_buf; + int ret = 0; + + file_dev = 0; +#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ + if ((stat(file, &st_buf) == 0) && + ext2fsP_is_disk_device(st_buf.st_mode)) + file_dev = st_buf.st_rdev; +#endif /* __GNU__ */ + + if (!(f = fopen("/proc/swaps", "r"))) + return 0; + /* Skip the first line */ + if (!fgets(buf, sizeof(buf), f)) + goto leave; + if (*buf && strncmp(buf, "Filename\t", 9)) + /* Linux <=2.6.19 contained a bug in the /proc/swaps + * code where the header would not be displayed + */ + goto valid_first_line; + + while (fgets(buf, sizeof(buf), f)) { +valid_first_line: + if ((cp = strchr(buf, ' ')) != NULL) + *cp = 0; + if ((cp = strchr(buf, '\t')) != NULL) + *cp = 0; + if (strcmp(buf, file) == 0) { + ret++; + break; + } +#ifndef __GNU__ + if (file_dev && (stat(buf, &st_buf) == 0) && + ext2fsP_is_disk_device(st_buf.st_mode) && + file_dev == st_buf.st_rdev) { + ret++; + break; + } +#endif /* __GNU__ */ + } + +leave: + fclose(f); + return ret; +} + + +/* + * ext2fs_check_mount_point() fills determines if the device is + * mounted or otherwise busy, and fills in mount_flags with one or + * more of the following flags: EXT2_MF_MOUNTED, EXT2_MF_ISROOT, + * EXT2_MF_READONLY, EXT2_MF_SWAP, and EXT2_MF_BUSY. If mtpt is + * non-NULL, the directory where the device is mounted is copied to + * where mtpt is pointing, up to mtlen characters. + */ +#ifdef __TURBOC__ + #pragma argsused +#endif +errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags, + char *mtpt, int mtlen) +{ + errcode_t retval = 0; + + if (getenv("EXT2FS_PRETEND_RO_MOUNT")) { + *mount_flags = EXT2_MF_MOUNTED | EXT2_MF_READONLY; + if (getenv("EXT2FS_PRETEND_ROOTFS")) + *mount_flags = EXT2_MF_ISROOT; + return 0; + } + if (getenv("EXT2FS_PRETEND_RW_MOUNT")) { + *mount_flags = EXT2_MF_MOUNTED; + if (getenv("EXT2FS_PRETEND_ROOTFS")) + *mount_flags = EXT2_MF_ISROOT; + return 0; + } + + if (is_swap_device(device)) { + *mount_flags = EXT2_MF_MOUNTED | EXT2_MF_SWAP; + strncpy(mtpt, "", mtlen); + } else { +#ifdef HAVE_SETMNTENT + retval = check_mntent(device, mount_flags, mtpt, mtlen); +#else +#ifdef HAVE_GETMNTINFO + retval = check_getmntinfo(device, mount_flags, mtpt, mtlen); +#else +#ifdef __GNUC__ + #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!" +#endif + *mount_flags = 0; +#endif /* HAVE_GETMNTINFO */ +#endif /* HAVE_SETMNTENT */ + } + if (retval) + return retval; + +#ifdef __linux__ /* This only works on Linux 2.6+ systems */ + { + struct stat st_buf; + + if (stat(device, &st_buf) == 0 && + ext2fsP_is_disk_device(st_buf.st_mode)) { + int fd = open(device, O_RDONLY | O_EXCL); + + if (fd >= 0) + close(fd); + else if (errno == EBUSY) + *mount_flags |= EXT2_MF_BUSY; + } + } +#endif + + return 0; +} + +/* + * ext2fs_check_if_mounted() sets the mount_flags EXT2_MF_MOUNTED, + * EXT2_MF_READONLY, and EXT2_MF_ROOT + * + */ +errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags) +{ + return ext2fs_check_mount_point(file, mount_flags, NULL, 0); +} + +#ifdef DEBUG +int main(int argc, char **argv) +{ + int retval, mount_flags; + char mntpt[80]; + + if (argc < 2) { + fprintf(stderr, "Usage: %s device\n", argv[0]); + exit(1); + } + + add_error_table(&et_ext2_error_table); + mntpt[0] = 0; + retval = ext2fs_check_mount_point(argv[1], &mount_flags, + mntpt, sizeof(mntpt)); + if (retval) { + com_err(argv[0], retval, + "while calling ext2fs_check_if_mounted"); + exit(1); + } + printf("Device %s reports flags %02x\n", argv[1], mount_flags); + if (mount_flags & EXT2_MF_BUSY) + printf("\t%s is apparently in use.\n", argv[1]); + if (mount_flags & EXT2_MF_MOUNTED) + printf("\t%s is mounted.\n", argv[1]); + if (mount_flags & EXT2_MF_SWAP) + printf("\t%s is a swap device.\n", argv[1]); + if (mount_flags & EXT2_MF_READONLY) + printf("\t%s is read-only.\n", argv[1]); + if (mount_flags & EXT2_MF_ISROOT) + printf("\t%s is the root filesystem.\n", argv[1]); + if (mntpt[0]) + printf("\t%s is mounted on %s.\n", argv[1], mntpt); + exit(0); +} +#endif /* DEBUG */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/jfs_compat.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/jfs_compat.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,99 @@ + +#ifndef _JFS_COMPAT_H +#define _JFS_COMPAT_H + +#include "kernel-list.h" +#include +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_WINSOCK_H +#include +#else +#include +#endif + +#define printk printf +#define KERN_ERR "" +#define KERN_DEBUG "" + +#define READ 0 +#define WRITE 1 + +#define cpu_to_be32(n) htonl(n) +#define be32_to_cpu(n) ntohl(n) +#define cpu_to_be16(n) htons(n) +#define be16_to_cpu(n) ntohs(n) + +typedef unsigned int tid_t; +typedef struct journal_s journal_t; +typedef struct kdev_s *kdev_t; + +struct buffer_head; +struct inode; + +#define GFP_KERNEL 0 +#define JFS_TAG_SIZE32 JBD_TAG_SIZE32 +#define JFS_BARRIER 0 +typedef __u64 u64; +#define JFS_CRC32_CHKSUM JBD2_CRC32_CHKSUM +#define JFS_CRC32_CHKSUM_SIZE JBD2_CRC32_CHKSUM_SIZE +#define put_bh(x) brelse(x) +#define be64_to_cpu(x) ext2fs_be64_to_cpu(x) + +static inline __u32 jbd2_chksum(journal_t *j EXT2FS_ATTR((unused)), + __u32 crc, const void *address, + unsigned int length) +{ + return ext2fs_crc32c_le(crc, address, length); +} +#define crc32_be(x, y, z) ext2fs_crc32_be((x), (y), (z)) +#define spin_lock_init(x) +#define spin_lock(x) +#define spin_unlock(x) +#define yield() +#define SLAB_HWCACHE_ALIGN 0 +#define SLAB_TEMPORARY 0 +#define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\ + sizeof(struct __struct), __alignof__(struct __struct),\ + (__flags), NULL) + +#define blkdev_issue_flush(kdev, a, b) sync_blockdev(kdev) +#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) + +struct journal_s +{ + unsigned long j_flags; + int j_errno; + struct buffer_head * j_sb_buffer; + struct journal_superblock_s *j_superblock; + int j_format_version; + unsigned long j_head; + unsigned long j_tail; + unsigned long j_free; + unsigned long j_first, j_last; + kdev_t j_dev; + kdev_t j_fs_dev; + int j_blocksize; + unsigned int j_blk_offset; + unsigned int j_maxlen; + struct inode * j_inode; + tid_t j_tail_sequence; + tid_t j_transaction_sequence; + __u8 j_uuid[16]; + struct jbd2_revoke_table_s *j_revoke; + struct jbd2_revoke_table_s *j_revoke_table[2]; + tid_t j_failed_commit; + __u32 j_csum_seed; +}; + +#define is_journal_abort(x) 0 + +#define BUFFER_TRACE(bh, info) do {} while (0) + +/* Need this so we can compile with configure --enable-gcc-wall */ +#ifdef NO_INLINE_FUNCS +#define inline +#endif + +#endif /* _JFS_COMPAT_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/kernel-list.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/kernel-list.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,109 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +/* + * 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 INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +#if (!defined(__GNUC__) && !defined(__WATCOMC__)) +#define __inline__ +#endif + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +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; +} + +/* + * Insert a new entry after the specified head.. + */ +static __inline__ void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/* + * Insert a new entry at the tail + */ +static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, 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; +} + +static __inline__ void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +static __inline__ int list_empty(struct list_head *head) +{ + return head->next == head; +} + +/* + * Splice in "list" into "head" + */ +static __inline__ void list_splice(struct list_head *list, struct list_head *head) +{ + struct list_head *first = list->next; + + if (first != list) { + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; + } +} + +#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/link.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/link.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,201 @@ +/* + * link.c --- create links in a ext2fs directory + * + * Copyright (C) 1993, 1994 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +struct link_struct { + ext2_filsys fs; + const char *name; + int namelen; + ext2_ino_t inode; + int flags; + int done; + unsigned int blocksize; + errcode_t err; + struct ext2_super_block *sb; +}; + +static int link_proc(struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data) +{ + struct link_struct *ls = (struct link_struct *) priv_data; + struct ext2_dir_entry *next; + unsigned int rec_len, min_rec_len, curr_rec_len; + int ret = 0; + int csum_size = 0; + struct ext2_dir_entry_tail *t; + + if (ls->done) + return DIRENT_ABORT; + + rec_len = EXT2_DIR_REC_LEN(ls->namelen); + + ls->err = ext2fs_get_rec_len(ls->fs, dirent, &curr_rec_len); + if (ls->err) + return DIRENT_ABORT; + + if (ext2fs_has_feature_metadata_csum(ls->fs->super)) + csum_size = sizeof(struct ext2_dir_entry_tail); + /* + * See if the following directory entry (if any) is unused; + * if so, absorb it into this one. + */ + next = (struct ext2_dir_entry *) (buf + offset + curr_rec_len); + if ((offset + (int) curr_rec_len < blocksize - (8 + csum_size)) && + (next->inode == 0) && + (offset + (int) curr_rec_len + (int) next->rec_len <= blocksize)) { + curr_rec_len += next->rec_len; + ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent); + if (ls->err) + return DIRENT_ABORT; + ret = DIRENT_CHANGED; + } + + /* + * Since ext2fs_link blows away htree data, we need to be + * careful -- if metadata_csum is enabled and we're passed in + * a dirent that contains htree data, we need to create the + * fake entry at the end of the block that hides the checksum. + */ + + /* De-convert a dx_node block */ + if (csum_size && + curr_rec_len == ls->fs->blocksize && + !dirent->inode) { + curr_rec_len -= csum_size; + ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent); + if (ls->err) + return DIRENT_ABORT; + t = EXT2_DIRENT_TAIL(buf, ls->fs->blocksize); + ext2fs_initialize_dirent_tail(ls->fs, t); + ret = DIRENT_CHANGED; + } + + /* De-convert a dx_root block */ + if (csum_size && + curr_rec_len == ls->fs->blocksize - EXT2_DIR_REC_LEN(1) && + offset == EXT2_DIR_REC_LEN(1) && + dirent->name[0] == '.' && dirent->name[1] == '.') { + curr_rec_len -= csum_size; + ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent); + if (ls->err) + return DIRENT_ABORT; + t = EXT2_DIRENT_TAIL(buf, ls->fs->blocksize); + ext2fs_initialize_dirent_tail(ls->fs, t); + ret = DIRENT_CHANGED; + } + + /* + * If the directory entry is used, see if we can split the + * directory entry to make room for the new name. If so, + * truncate it and return. + */ + if (dirent->inode) { + min_rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(dirent)); + if (curr_rec_len < (min_rec_len + rec_len)) + return ret; + rec_len = curr_rec_len - min_rec_len; + ls->err = ext2fs_set_rec_len(ls->fs, min_rec_len, dirent); + if (ls->err) + return DIRENT_ABORT; + next = (struct ext2_dir_entry *) (buf + offset + + dirent->rec_len); + next->inode = 0; + ext2fs_dirent_set_name_len(next, 0); + ext2fs_dirent_set_file_type(next, 0); + ls->err = ext2fs_set_rec_len(ls->fs, rec_len, next); + if (ls->err) + return DIRENT_ABORT; + return DIRENT_CHANGED; + } + + /* + * If we get this far, then the directory entry is not used. + * See if we can fit the request entry in. If so, do it. + */ + if (curr_rec_len < rec_len) + return ret; + dirent->inode = ls->inode; + ext2fs_dirent_set_name_len(dirent, ls->namelen); + strncpy(dirent->name, ls->name, ls->namelen); + if (ext2fs_has_feature_filetype(ls->sb)) + ext2fs_dirent_set_file_type(dirent, ls->flags & 0x7); + + ls->done++; + return DIRENT_ABORT|DIRENT_CHANGED; +} + +/* + * Note: the low 3 bits of the flags field are used as the directory + * entry filetype. + */ +#ifdef __TURBOC__ + #pragma argsused +#endif +errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, + ext2_ino_t ino, int flags) +{ + errcode_t retval; + struct link_struct ls; + struct ext2_inode inode; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!(fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + ls.fs = fs; + ls.name = name; + ls.namelen = name ? strlen(name) : 0; + ls.inode = ino; + ls.flags = flags; + ls.done = 0; + ls.sb = fs->super; + ls.blocksize = fs->blocksize; + ls.err = 0; + + retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY, + 0, link_proc, &ls); + if (retval) + return retval; + if (ls.err) + return ls.err; + + if (!ls.done) + return EXT2_ET_DIR_NO_SPACE; + + if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0) + return retval; + + /* + * If this function changes to preserve the htree, remove the + * two hunks in link_proc that shove checksum tails into the + * former dx_root/dx_node blocks. + */ + if (inode.i_flags & EXT2_INDEX_FL) { + inode.i_flags &= ~EXT2_INDEX_FL; + if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0) + return retval; + } + + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/llseek.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/llseek.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,145 @@ +/* + * llseek.c -- stub calling the llseek system call + * + * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#include "config.h" +#if HAVE_SYS_TYPES_H +#include +#endif + +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#ifdef __MSDOS__ +#include +#endif +#include "et/com_err.h" +#include "ext2fs/ext2_io.h" + +#ifdef __linux__ + +#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) + +#define my_llseek lseek64 + +#else +#if defined(HAVE_LLSEEK) +#include + +#ifndef HAVE_LLSEEK_PROTOTYPE +extern long long llseek (int fd, long long offset, int origin); +#endif + +#define my_llseek llseek + +#else /* ! HAVE_LLSEEK */ + +#if SIZEOF_LONG == SIZEOF_LONG_LONG + +#define my_llseek lseek + +#else /* SIZEOF_LONG != SIZEOF_LONG_LONG */ + +#include + +#ifndef __NR__llseek +#define __NR__llseek 140 +#endif + +#ifndef __i386__ +static int _llseek (unsigned int, unsigned long, + unsigned long, ext2_loff_t *, unsigned int); + +static _syscall5(int,_llseek,unsigned int,fd,unsigned long,offset_high, + unsigned long, offset_low,ext2_loff_t *,result, + unsigned int, origin) +#endif + +static ext2_loff_t my_llseek (int fd, ext2_loff_t offset, int origin) +{ + ext2_loff_t result; + int retval; + +#ifndef __i386__ + retval = _llseek(fd, ((unsigned long long) offset) >> 32, +#else + retval = syscall(__NR__llseek, fd, (unsigned long long) (offset >> 32), +#endif + ((unsigned long long) offset) & 0xffffffff, + &result, origin); + return (retval == -1 ? (ext2_loff_t) retval : result); +} + +#endif /* SIZE_LONG == SIZEOF_LONG_LONG */ + +#endif /* HAVE_LLSEEK */ +#endif /* defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) */ + +ext2_loff_t ext2fs_llseek (int fd, ext2_loff_t offset, int origin) +{ +#if SIZEOF_OFF_T >= SIZEOF_LONG_LONG + return my_llseek (fd, offset, origin); +#else + ext2_loff_t result; + static int do_compat = 0; + + if (do_compat) + goto fallback; + + result = my_llseek (fd, offset, origin); + if (result == -1 && errno == ENOSYS) { + /* + * Just in case this code runs on top of an old kernel + * which does not support the llseek system call + */ + do_compat++; + fallback: + if (offset < ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1))) + return lseek(fd, (off_t) offset, origin); + errno = EINVAL; + return -1; + } + return result; +#endif +} + +#else /* !linux */ + +#ifndef EINVAL +#define EINVAL EXT2_ET_INVALID_ARGUMENT +#endif + +ext2_loff_t ext2fs_llseek (int fd, ext2_loff_t offset, int origin) +{ +#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) + return lseek64 (fd, offset, origin); +#else + if ((sizeof(off_t) < sizeof(ext2_loff_t)) && + (offset >= ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) { + errno = EINVAL; + return -1; + } + return lseek (fd, (off_t) offset, origin); +#endif +} + +#endif /* linux */ + + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/lookup.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/lookup.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,70 @@ +/* + * lookup.c --- ext2fs directory lookup operations + * + * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +struct lookup_struct { + const char *name; + int len; + ext2_ino_t *inode; + int found; +}; + +#ifdef __TURBOC__ + #pragma argsused +#endif +static int lookup_proc(struct ext2_dir_entry *dirent, + int offset EXT2FS_ATTR((unused)), + int blocksize EXT2FS_ATTR((unused)), + char *buf EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct lookup_struct *ls = (struct lookup_struct *) priv_data; + + if (ls->len != ext2fs_dirent_name_len(dirent)) + return 0; + if (strncmp(ls->name, dirent->name, ext2fs_dirent_name_len(dirent))) + return 0; + *ls->inode = dirent->inode; + ls->found++; + return DIRENT_ABORT; +} + + +errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name, + int namelen, char *buf, ext2_ino_t *inode) +{ + errcode_t retval; + struct lookup_struct ls; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + ls.name = name; + ls.len = namelen; + ls.inode = inode; + ls.found = 0; + + retval = ext2fs_dir_iterate(fs, dir, 0, buf, lookup_proc, &ls); + if (retval) + return retval; + + return (ls.found) ? 0 : EXT2_ET_FILE_NOT_FOUND; +} + + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/mkdir.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/mkdir.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,192 @@ +/* + * mkdir.c --- make a directory in the filesystem + * + * Copyright (C) 1994, 1995 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +#ifndef EXT2_FT_DIR +#define EXT2_FT_DIR 2 +#endif + +errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, + const char *name) +{ + ext2_extent_handle_t handle; + errcode_t retval; + struct ext2_inode parent_inode, inode; + ext2_ino_t ino = inum; + ext2_ino_t scratch_ino; + blk64_t blk; + char *block = 0; + int inline_data = 0; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + /* + * Create a new dir with inline data iff this feature is enabled + * and ino >= EXT2_FIRST_INO. + */ + if ((!ino || ino >= EXT2_FIRST_INO(fs->super)) && + ext2fs_has_feature_inline_data(fs->super)) + inline_data = 1; + + /* + * Allocate an inode, if necessary + */ + if (!ino) { + retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755, + 0, &ino); + if (retval) + goto cleanup; + } + + /* + * Allocate a data block for the directory + */ + memset(&inode, 0, sizeof(struct ext2_inode)); + if (!inline_data) { + retval = ext2fs_new_block2(fs, ext2fs_find_inode_goal(fs, ino, + &inode, + 0), + NULL, &blk); + if (retval) + goto cleanup; + } + + /* + * Create a scratch template for the directory + */ + if (inline_data) + retval = ext2fs_new_dir_inline_data(fs, ino, parent, + inode.i_block); + else + retval = ext2fs_new_dir_block(fs, ino, parent, &block); + if (retval) + goto cleanup; + + /* + * Get the parent's inode, if necessary + */ + if (parent != ino) { + retval = ext2fs_read_inode(fs, parent, &parent_inode); + if (retval) + goto cleanup; + } else + memset(&parent_inode, 0, sizeof(parent_inode)); + + /* + * Create the inode structure.... + */ + inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask); + inode.i_uid = inode.i_gid = 0; + if (inline_data) { + inode.i_flags |= EXT4_INLINE_DATA_FL; + inode.i_size = EXT4_MIN_INLINE_DATA_SIZE; + } else { + if (ext2fs_has_feature_extents(fs->super)) + inode.i_flags |= EXT4_EXTENTS_FL; + else + inode.i_block[0] = blk; + inode.i_size = fs->blocksize; + ext2fs_iblk_set(fs, &inode, 1); + } + inode.i_links_count = 2; + + /* + * Write out the inode and inode data block. The inode generation + * number is assigned by write_new_inode, which means that the call + * to write_dir_block must come after that. + */ + retval = ext2fs_write_new_inode(fs, ino, &inode); + if (retval) + goto cleanup; + if (inline_data) { + /* init "system.data" for new dir */ + retval = ext2fs_inline_data_init(fs, ino); + } else { + retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); + if (retval) + goto cleanup; + + if (ext2fs_has_feature_extents(fs->super)) { + retval = ext2fs_extent_open2(fs, ino, &inode, &handle); + if (retval) + goto cleanup; + retval = ext2fs_extent_set_bmap(handle, 0, blk, 0); + ext2fs_extent_free(handle); + if (retval) + goto cleanup; + } + } + + /* + * Link the directory into the filesystem hierarchy + */ + if (name) { + retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, + &scratch_ino); + if (!retval) { + retval = EXT2_ET_DIR_EXISTS; + name = 0; + goto cleanup; + } + if (retval != EXT2_ET_FILE_NOT_FOUND) + goto cleanup; + retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR); + if (retval) + goto cleanup; + } + + /* + * Update parent inode's counts + */ + if (parent != ino) { + /* reload parent inode due to inline data */ + retval = ext2fs_read_inode(fs, parent, &parent_inode); + if (retval) + goto cleanup; + parent_inode.i_links_count++; + retval = ext2fs_write_inode(fs, parent, &parent_inode); + if (retval) + goto cleanup; + } + + /* + * Update accounting.... + */ + if (!inline_data) + ext2fs_block_alloc_stats2(fs, blk, +1); + ext2fs_inode_alloc_stats2(fs, ino, +1, 1); + +cleanup: + if (block) + ext2fs_free_mem(&block); + return retval; + +} + + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/mkjournal.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/mkjournal.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,589 @@ +/* + * mkjournal.c --- make a journal for a filesystem + * + * Copyright (C) 2000 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_IOCTL_H +#include +#endif +#if HAVE_NETINET_IN_H +#include +#endif + +#include "ext2_fs.h" +#include "e2p/e2p.h" +#include "ext2fs.h" + +#include "kernel-jbd.h" + +/* + * This function automatically sets up the journal superblock and + * returns it as an allocated block. + */ +errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, + __u32 num_blocks, int flags, + char **ret_jsb) +{ + errcode_t retval; + journal_superblock_t *jsb; + + if (num_blocks < JFS_MIN_JOURNAL_BLOCKS) + return EXT2_ET_JOURNAL_TOO_SMALL; + + if ((retval = ext2fs_get_mem(fs->blocksize, &jsb))) + return retval; + + memset (jsb, 0, fs->blocksize); + + jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); + if (flags & EXT2_MKJOURNAL_V1_SUPER) + jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1); + else + jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2); + jsb->s_blocksize = htonl(fs->blocksize); + jsb->s_maxlen = htonl(num_blocks); + jsb->s_nr_users = htonl(1); + jsb->s_first = htonl(1); + jsb->s_sequence = htonl(1); + memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid)); + /* + * If we're creating an external journal device, we need to + * adjust these fields. + */ + if (ext2fs_has_feature_journal_dev(fs->super)) { + jsb->s_nr_users = 0; + jsb->s_first = htonl(ext2fs_journal_sb_start(fs->blocksize) + 1); + } + + *ret_jsb = (char *) jsb; + return 0; +} + +/* + * This function writes a journal using POSIX routines. It is used + * for creating external journals and creating journals on live + * filesystems. + */ +static errcode_t write_journal_file(ext2_filsys fs, char *filename, + blk_t num_blocks, int flags) +{ + errcode_t retval; + char *buf = 0; + int fd, ret_size; + blk_t i; + + if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags, + &buf))) + return retval; + + /* Open the device or journal file */ + if ((fd = open(filename, O_WRONLY)) < 0) { + retval = errno; + goto errfree; + } + + /* Write the superblock out */ + retval = EXT2_ET_SHORT_WRITE; + ret_size = write(fd, buf, fs->blocksize); + if (ret_size < 0) { + retval = errno; + goto errout; + } + if (ret_size != (int) fs->blocksize) + goto errout; + memset(buf, 0, fs->blocksize); + + if (flags & EXT2_MKJOURNAL_LAZYINIT) + goto success; + + for (i = 1; i < num_blocks; i++) { + ret_size = write(fd, buf, fs->blocksize); + if (ret_size < 0) { + retval = errno; + goto errout; + } + if (ret_size != (int) fs->blocksize) + goto errout; + } + +success: + retval = 0; +errout: + close(fd); +errfree: + ext2fs_free_mem(&buf); + return retval; +} + +/* + * Convenience function which zeros out _num_ blocks starting at + * _blk_. In case of an error, the details of the error is returned + * via _ret_blk_ and _ret_count_ if they are non-NULL pointers. + * Returns 0 on success, and an error code on an error. + * + * As a special case, if the first argument is NULL, then it will + * attempt to free the static zeroizing buffer. (This is to keep + * programs that check for memory leaks happy.) + */ +#define MAX_STRIDE_LENGTH (4194304 / (int) fs->blocksize) +errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num, + blk64_t *ret_blk, int *ret_count) +{ + int j, count; + static void *buf; + static int stride_length; + errcode_t retval; + + /* If fs is null, clean up the static buffer and return */ + if (!fs) { + if (buf) { + free(buf); + buf = 0; + stride_length = 0; + } + return 0; + } + + /* Deal with zeroing less than 1 block */ + if (num <= 0) + return 0; + + /* Try a zero out command, if supported */ + retval = io_channel_zeroout(fs->io, blk, num); + if (retval == 0) + return 0; + + /* Allocate the zeroizing buffer if necessary */ + if (num > stride_length && stride_length < MAX_STRIDE_LENGTH) { + void *p; + int new_stride = num; + + if (new_stride > MAX_STRIDE_LENGTH) + new_stride = MAX_STRIDE_LENGTH; + p = realloc(buf, fs->blocksize * new_stride); + if (!p) + return EXT2_ET_NO_MEMORY; + buf = p; + stride_length = new_stride; + memset(buf, 0, fs->blocksize * stride_length); + } + /* OK, do the write loop */ + j=0; + while (j < num) { + if (blk % stride_length) { + count = stride_length - (blk % stride_length); + if (count > (num - j)) + count = num - j; + } else { + count = num - j; + if (count > stride_length) + count = stride_length; + } + retval = io_channel_write_blk64(fs->io, blk, count, buf); + if (retval) { + if (ret_count) + *ret_count = count; + if (ret_blk) + *ret_blk = blk; + return retval; + } + j += count; blk += count; + } + return 0; +} + +errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num, + blk_t *ret_blk, int *ret_count) +{ + blk64_t ret_blk2; + errcode_t retval; + + retval = ext2fs_zero_blocks2(fs, blk, num, &ret_blk2, ret_count); + if (retval) + *ret_blk = (blk_t) ret_blk2; + return retval; +} + +/* + * Calculate the initial goal block to be roughly at the middle of the + * filesystem. Pick a group that has the largest number of free + * blocks. + */ +static blk64_t get_midpoint_journal_block(ext2_filsys fs) +{ + dgrp_t group, start, end, i, log_flex; + + group = ext2fs_group_of_blk2(fs, (ext2fs_blocks_count(fs->super) - + fs->super->s_first_data_block) / 2); + log_flex = 1 << fs->super->s_log_groups_per_flex; + if (fs->super->s_log_groups_per_flex && (group > log_flex)) { + group = group & ~(log_flex - 1); + while ((group < fs->group_desc_count) && + ext2fs_bg_free_blocks_count(fs, group) == 0) + group++; + if (group == fs->group_desc_count) + group = 0; + start = group; + } else + start = (group > 0) ? group-1 : group; + end = ((group+1) < fs->group_desc_count) ? group+1 : group; + group = start; + for (i = start + 1; i <= end; i++) + if (ext2fs_bg_free_blocks_count(fs, i) > + ext2fs_bg_free_blocks_count(fs, group)) + group = i; + return ext2fs_group_first_block2(fs, group); +} + +/* + * This function creates a journal using direct I/O routines. + */ +static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, + blk_t num_blocks, blk64_t goal, int flags) +{ + char *buf; + errcode_t retval; + struct ext2_inode inode; + unsigned long long inode_size; + int falloc_flags = EXT2_FALLOCATE_FORCE_INIT; + blk64_t zblk; + + if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags, + &buf))) + return retval; + + if ((retval = ext2fs_read_bitmaps(fs))) + goto out2; + + if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) + goto out2; + + if (inode.i_blocks > 0) { + retval = EEXIST; + goto out2; + } + + if (goal == ~0ULL) + goal = get_midpoint_journal_block(fs); + + if (ext2fs_has_feature_extents(fs->super)) + inode.i_flags |= EXT4_EXTENTS_FL; + + if (!(flags & EXT2_MKJOURNAL_LAZYINIT)) + falloc_flags |= EXT2_FALLOCATE_ZERO_BLOCKS; + + inode_size = (unsigned long long)fs->blocksize * num_blocks; + inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0); + inode.i_links_count = 1; + inode.i_mode = LINUX_S_IFREG | 0600; + retval = ext2fs_inode_size_set(fs, &inode, inode_size); + if (retval) + goto out2; + + retval = ext2fs_fallocate(fs, falloc_flags, journal_ino, + &inode, goal, 0, num_blocks); + if (retval) + goto out2; + + if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode))) + goto out2; + + retval = ext2fs_bmap2(fs, journal_ino, &inode, NULL, 0, 0, NULL, &zblk); + if (retval) + goto out2; + + retval = io_channel_write_blk64(fs->io, zblk, 1, buf); + if (retval) + goto out2; + + memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4); + fs->super->s_jnl_blocks[15] = inode.i_size_high; + fs->super->s_jnl_blocks[16] = inode.i_size; + fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; + ext2fs_mark_super_dirty(fs); + +out2: + ext2fs_free_mem(&buf); + return retval; +} + +/* + * Find a reasonable journal file size (in blocks) given the number of blocks + * in the filesystem. For very small filesystems, it is not reasonable to + * have a journal that fills more than half of the filesystem. + * + * n.b. comments assume 4k blocks + */ +int ext2fs_default_journal_size(__u64 num_blocks) +{ + if (num_blocks < 2048) + return -1; + if (num_blocks < 32768) /* 128 MB */ + return (1024); /* 4 MB */ + if (num_blocks < 256*1024) /* 1 GB */ + return (4096); /* 16 MB */ + if (num_blocks < 512*1024) /* 2 GB */ + return (8192); /* 32 MB */ + if (num_blocks < 4096*1024) /* 16 GB */ + return (16384); /* 64 MB */ + if (num_blocks < 8192*1024) /* 32 GB */ + return (32768); /* 128 MB */ + if (num_blocks < 16384*1024) /* 64 GB */ + return (65536); /* 256 MB */ + if (num_blocks < 32768*1024) /* 128 GB */ + return (131072); /* 512 MB */ + return 262144; /* 1 GB */ +} + +int ext2fs_journal_sb_start(int blocksize) +{ + if (blocksize == EXT2_MIN_BLOCK_SIZE) + return 2; + return 1; +} + +/* + * This function adds a journal device to a filesystem + */ +errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) +{ + struct stat st; + errcode_t retval; + char buf[SUPERBLOCK_SIZE]; + journal_superblock_t *jsb; + int start; + __u32 i, nr_users; + + /* Make sure the device exists and is a block device */ + if (stat(journal_dev->device_name, &st) < 0) + return errno; + + if (!S_ISBLK(st.st_mode)) + return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */ + + /* Get the journal superblock */ + start = ext2fs_journal_sb_start(journal_dev->blocksize); + if ((retval = io_channel_read_blk64(journal_dev->io, start, + -SUPERBLOCK_SIZE, + buf))) + return retval; + + jsb = (journal_superblock_t *) buf; + if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) || + (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) + return EXT2_ET_NO_JOURNAL_SB; + + if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize) + return EXT2_ET_UNEXPECTED_BLOCK_SIZE; + + /* Check and see if this filesystem has already been added */ + nr_users = ntohl(jsb->s_nr_users); + if (nr_users > JFS_USERS_MAX) + return EXT2_ET_CORRUPT_JOURNAL_SB; + for (i=0; i < nr_users; i++) { + if (memcmp(fs->super->s_uuid, + &jsb->s_users[i*16], 16) == 0) + break; + } + if (i >= nr_users) { + memcpy(&jsb->s_users[nr_users*16], + fs->super->s_uuid, 16); + jsb->s_nr_users = htonl(nr_users+1); + } + + /* Writeback the journal superblock */ + if ((retval = io_channel_write_blk64(journal_dev->io, start, + -SUPERBLOCK_SIZE, buf))) + return retval; + + fs->super->s_journal_inum = 0; + fs->super->s_journal_dev = st.st_rdev; + memcpy(fs->super->s_journal_uuid, jsb->s_uuid, + sizeof(fs->super->s_journal_uuid)); + memset(fs->super->s_jnl_blocks, 0, sizeof(fs->super->s_jnl_blocks)); + ext2fs_set_feature_journal(fs->super); + ext2fs_mark_super_dirty(fs); + return 0; +} + +/* + * This function adds a journal inode to a filesystem, using either + * POSIX routines if the filesystem is mounted, or using direct I/O + * functions if it is not. + */ +errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks, + blk64_t goal, int flags) +{ + errcode_t retval; + ext2_ino_t journal_ino; + struct stat st; + char jfile[1024]; + int mount_flags; + int fd = -1; + + if (flags & EXT2_MKJOURNAL_NO_MNT_CHECK) + mount_flags = 0; + else if ((retval = ext2fs_check_mount_point(fs->device_name, + &mount_flags, + jfile, sizeof(jfile)-10))) + return retval; + + if (mount_flags & EXT2_MF_MOUNTED) { +#if HAVE_EXT2_IOCTLS + int f = 0; +#endif + strcat(jfile, "/.journal"); + + /* + * If .../.journal already exists, make sure any + * immutable or append-only flags are cleared. + */ +#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP) + (void) chflags (jfile, 0); +#else +#if HAVE_EXT2_IOCTLS + fd = open(jfile, O_RDONLY); + if (fd >= 0) { + retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f); + close(fd); + if (retval) + return retval; + } +#endif +#endif + + /* Create the journal file */ + if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0) + return errno; + + /* Note that we can't do lazy journal initialization for mounted + * filesystems, since the zero writing is also allocating the + * journal blocks. We could use fallocate, but not all kernels + * support that, and creating a journal on a mounted ext2 + * filesystems is extremely rare these days... Ignore it. */ + flags &= ~EXT2_MKJOURNAL_LAZYINIT; + + if ((retval = write_journal_file(fs, jfile, num_blocks, flags))) + goto errout; + + /* Get inode number of the journal file */ + if (fstat(fd, &st) < 0) { + retval = errno; + goto errout; + } + +#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP) + retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE); +#else +#if HAVE_EXT2_IOCTLS + if (ioctl(fd, EXT2_IOC_GETFLAGS, &f) < 0) { + retval = errno; + goto errout; + } + f |= EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL; + retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f); +#endif +#endif + if (retval) { + retval = errno; + goto errout; + } + + if (close(fd) < 0) { + retval = errno; + fd = -1; + goto errout; + } + journal_ino = st.st_ino; + memset(fs->super->s_jnl_blocks, 0, + sizeof(fs->super->s_jnl_blocks)); + } else { + if ((mount_flags & EXT2_MF_BUSY) && + !(fs->flags & EXT2_FLAG_EXCLUSIVE)) { + retval = EBUSY; + goto errout; + } + journal_ino = EXT2_JOURNAL_INO; + if ((retval = write_journal_inode(fs, journal_ino, + num_blocks, goal, flags))) + return retval; + } + + fs->super->s_journal_inum = journal_ino; + fs->super->s_journal_dev = 0; + memset(fs->super->s_journal_uuid, 0, + sizeof(fs->super->s_journal_uuid)); + ext2fs_set_feature_journal(fs->super); + + ext2fs_mark_super_dirty(fs); + return 0; +errout: + if (fd >= 0) + close(fd); + return retval; +} + +errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags) +{ + return ext2fs_add_journal_inode2(fs, num_blocks, ~0ULL, flags); +} + + +#ifdef DEBUG +main(int argc, char **argv) +{ + errcode_t retval; + char *device_name; + ext2_filsys fs; + + if (argc < 2) { + fprintf(stderr, "Usage: %s filesystem\n", argv[0]); + exit(1); + } + device_name = argv[1]; + + retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0, + unix_io_manager, &fs); + if (retval) { + com_err(argv[0], retval, "while opening %s", device_name); + exit(1); + } + + retval = ext2fs_add_journal_inode(fs, JFS_MIN_JOURNAL_BLOCKS, 0); + if (retval) { + com_err(argv[0], retval, "while adding journal to %s", + device_name); + exit(1); + } + retval = ext2fs_flush(fs); + if (retval) { + printf("Warning, had trouble writing out superblocks.\n"); + } + ext2fs_close_free(&fs); + exit(0); + +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/mmp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/mmp.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,472 @@ +/* + * Helper functions for multiple mount protection (MMP). + * + * Copyright (C) 2011 Whamcloud, Inc. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE /* since glibc 2.20 _SVID_SOURCE is deprecated */ +#endif + +#include "config.h" + +#if HAVE_UNISTD_H +#include +#endif +#include + +#include +#include +#include + +#include "ext2fs/ext2_fs.h" +#include "ext2fs/ext2fs.h" + +#ifndef O_DIRECT +#define O_DIRECT 0 +#endif + +#if __GNUC_PREREQ (4, 6) +#pragma GCC diagnostic push +#ifndef CONFIG_MMP +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif +#endif + +errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf) +{ +#ifdef CONFIG_MMP + struct mmp_struct *mmp_cmp; + errcode_t retval = 0; + + if ((mmp_blk <= fs->super->s_first_data_block) || + (mmp_blk >= ext2fs_blocks_count(fs->super))) + return EXT2_ET_MMP_BAD_BLOCK; + + /* ext2fs_open() reserves fd0,1,2 to avoid stdio collision, so checking + * mmp_fd <= 0 is OK to validate that the fd is valid. This opens its + * own fd to read the MMP block to ensure that it is using O_DIRECT, + * regardless of how the io_manager is doing reads, to avoid caching of + * the MMP block by the io_manager or the VM. It needs to be fresh. */ + if (fs->mmp_fd <= 0) { + fs->mmp_fd = open(fs->device_name, O_RDWR | O_DIRECT); + if (fs->mmp_fd < 0) { + retval = EXT2_ET_MMP_OPEN_DIRECT; + goto out; + } + } + + if (fs->mmp_cmp == NULL) { + int align = ext2fs_get_dio_alignment(fs->mmp_fd); + + retval = ext2fs_get_memalign(fs->blocksize, align, + &fs->mmp_cmp); + if (retval) + return retval; + } + + if ((blk64_t) ext2fs_llseek(fs->mmp_fd, mmp_blk * fs->blocksize, + SEEK_SET) != + mmp_blk * fs->blocksize) { + retval = EXT2_ET_LLSEEK_FAILED; + goto out; + } + + if (read(fs->mmp_fd, fs->mmp_cmp, fs->blocksize) != fs->blocksize) { + retval = EXT2_ET_SHORT_READ; + goto out; + } + + mmp_cmp = fs->mmp_cmp; + + if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_mmp_csum_verify(fs, mmp_cmp)) + retval = EXT2_ET_MMP_CSUM_INVALID; + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_mmp(mmp_cmp); +#endif + + if (buf != NULL && buf != fs->mmp_cmp) + memcpy(buf, fs->mmp_cmp, fs->blocksize); + + if (mmp_cmp->mmp_magic != EXT4_MMP_MAGIC) { + retval = EXT2_ET_MMP_MAGIC_INVALID; + goto out; + } + +out: + return retval; +#else + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +errcode_t ext2fs_mmp_write(ext2_filsys fs, blk64_t mmp_blk, void *buf) +{ +#ifdef CONFIG_MMP + struct mmp_struct *mmp_s = buf; + struct timeval tv; + errcode_t retval = 0; + + gettimeofday(&tv, 0); + mmp_s->mmp_time = tv.tv_sec; + fs->mmp_last_written = tv.tv_sec; + + if (fs->super->s_mmp_block < fs->super->s_first_data_block || + fs->super->s_mmp_block > ext2fs_blocks_count(fs->super)) + return EXT2_ET_MMP_BAD_BLOCK; + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_mmp(mmp_s); +#endif + + retval = ext2fs_mmp_csum_set(fs, mmp_s); + if (retval) + return retval; + + /* I was tempted to make this use O_DIRECT and the mmp_fd, but + * this caused no end of grief, while leaving it as-is works. */ + retval = io_channel_write_blk64(fs->io, mmp_blk, -(int)sizeof(struct mmp_struct), buf); + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_mmp(mmp_s); +#endif + + /* Make sure the block gets to disk quickly */ + io_channel_flush(fs->io); + return retval; +#else + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +#ifdef HAVE_SRANDOM +#define srand(x) srandom(x) +#define rand() random() +#endif + +unsigned ext2fs_mmp_new_seq(void) +{ +#ifdef CONFIG_MMP + unsigned new_seq; + struct timeval tv; + + gettimeofday(&tv, 0); + srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); + + gettimeofday(&tv, 0); + /* Crank the random number generator a few times */ + for (new_seq = (tv.tv_sec ^ tv.tv_usec) & 0x1F; new_seq > 0; new_seq--) + rand(); + + do { + new_seq = rand(); + } while (new_seq > EXT4_MMP_SEQ_MAX); + + return new_seq; +#else + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +#ifdef CONFIG_MMP +static errcode_t ext2fs_mmp_reset(ext2_filsys fs) +{ + struct mmp_struct *mmp_s = NULL; + errcode_t retval = 0; + + if (fs->mmp_buf == NULL) { + retval = ext2fs_get_mem(fs->blocksize, &fs->mmp_buf); + if (retval) + goto out; + } + + memset(fs->mmp_buf, 0, fs->blocksize); + mmp_s = fs->mmp_buf; + + mmp_s->mmp_magic = EXT4_MMP_MAGIC; + mmp_s->mmp_seq = EXT4_MMP_SEQ_CLEAN; + mmp_s->mmp_time = 0; +#ifdef HAVE_GETHOSTNAME + gethostname(mmp_s->mmp_nodename, sizeof(mmp_s->mmp_nodename)); +#else + mmp_s->mmp_nodename[0] = '\0'; +#endif + strncpy(mmp_s->mmp_bdevname, fs->device_name, + sizeof(mmp_s->mmp_bdevname)); + + mmp_s->mmp_check_interval = fs->super->s_mmp_update_interval; + if (mmp_s->mmp_check_interval < EXT4_MMP_MIN_CHECK_INTERVAL) + mmp_s->mmp_check_interval = EXT4_MMP_MIN_CHECK_INTERVAL; + + retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf); +out: + return retval; +} +#endif + +errcode_t ext2fs_mmp_update(ext2_filsys fs) +{ + return ext2fs_mmp_update2(fs, 0); +} + +errcode_t ext2fs_mmp_clear(ext2_filsys fs) +{ +#ifdef CONFIG_MMP + errcode_t retval = 0; + + if (!(fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + retval = ext2fs_mmp_reset(fs); + + return retval; +#else + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +errcode_t ext2fs_mmp_init(ext2_filsys fs) +{ +#ifdef CONFIG_MMP + struct ext2_super_block *sb = fs->super; + blk64_t mmp_block; + errcode_t retval; + + if (sb->s_mmp_update_interval == 0) + sb->s_mmp_update_interval = EXT4_MMP_UPDATE_INTERVAL; + /* This is probably excessively large, but who knows? */ + else if (sb->s_mmp_update_interval > EXT4_MMP_MAX_UPDATE_INTERVAL) + return EXT2_ET_INVALID_ARGUMENT; + + if (fs->mmp_buf == NULL) { + retval = ext2fs_get_mem(fs->blocksize, &fs->mmp_buf); + if (retval) + goto out; + } + + retval = ext2fs_alloc_block2(fs, 0, fs->mmp_buf, &mmp_block); + if (retval) + goto out; + + sb->s_mmp_block = mmp_block; + + retval = ext2fs_mmp_reset(fs); + if (retval) + goto out; + +out: + return retval; +#else + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +#ifndef min +#define min(x, y) ((x) < (y) ? (x) : (y)) +#endif + +/* + * Make sure that the fs is not mounted or being fsck'ed while opening the fs. + */ +errcode_t ext2fs_mmp_start(ext2_filsys fs) +{ +#ifdef CONFIG_MMP + struct mmp_struct *mmp_s; + unsigned seq; + unsigned int mmp_check_interval; + errcode_t retval = 0; + + if (fs->mmp_buf == NULL) { + retval = ext2fs_get_mem(fs->blocksize, &fs->mmp_buf); + if (retval) + goto mmp_error; + } + + retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf); + if (retval) + goto mmp_error; + + mmp_s = fs->mmp_buf; + + mmp_check_interval = fs->super->s_mmp_update_interval; + if (mmp_check_interval < EXT4_MMP_MIN_CHECK_INTERVAL) + mmp_check_interval = EXT4_MMP_MIN_CHECK_INTERVAL; + + seq = mmp_s->mmp_seq; + if (seq == EXT4_MMP_SEQ_CLEAN) + goto clean_seq; + if (seq == EXT4_MMP_SEQ_FSCK) { + retval = EXT2_ET_MMP_FSCK_ON; + goto mmp_error; + } + + if (seq > EXT4_MMP_SEQ_FSCK) { + retval = EXT2_ET_MMP_UNKNOWN_SEQ; + goto mmp_error; + } + + /* + * If check_interval in MMP block is larger, use that instead of + * check_interval from the superblock. + */ + if (mmp_s->mmp_check_interval > mmp_check_interval) + mmp_check_interval = mmp_s->mmp_check_interval; + + sleep(min(mmp_check_interval * 2 + 1, mmp_check_interval + 60)); + + retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf); + if (retval) + goto mmp_error; + + if (seq != mmp_s->mmp_seq) { + retval = EXT2_ET_MMP_FAILED; + goto mmp_error; + } + +clean_seq: + if (!(fs->flags & EXT2_FLAG_RW)) + goto mmp_error; + + mmp_s->mmp_seq = seq = ext2fs_mmp_new_seq(); +#ifdef HAVE_GETHOSTNAME + gethostname(mmp_s->mmp_nodename, sizeof(mmp_s->mmp_nodename)); +#else + strcpy(mmp_s->mmp_nodename, "unknown host"); +#endif + strncpy(mmp_s->mmp_bdevname, fs->device_name, + sizeof(mmp_s->mmp_bdevname)); + + retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf); + if (retval) + goto mmp_error; + + sleep(min(2 * mmp_check_interval + 1, mmp_check_interval + 60)); + + retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf); + if (retval) + goto mmp_error; + + if (seq != mmp_s->mmp_seq) { + retval = EXT2_ET_MMP_FAILED; + goto mmp_error; + } + + mmp_s->mmp_seq = EXT4_MMP_SEQ_FSCK; + retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf); + if (retval) + goto mmp_error; + + return 0; + +mmp_error: + return retval; +#else + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +/* + * Clear the MMP usage in the filesystem. If this function returns an + * error EXT2_ET_MMP_CHANGE_ABORT it means the filesystem was modified + * by some other process while in use, and changes should be dropped, or + * risk filesystem corruption. + */ +errcode_t ext2fs_mmp_stop(ext2_filsys fs) +{ +#ifdef CONFIG_MMP + struct mmp_struct *mmp, *mmp_cmp; + errcode_t retval = 0; + + if (!ext2fs_has_feature_mmp(fs->super) || + !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP)) + goto mmp_error; + + retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf); + if (retval) + goto mmp_error; + + /* Check if the MMP block is not changed. */ + mmp = fs->mmp_buf; + mmp_cmp = fs->mmp_cmp; + if (memcmp(mmp, mmp_cmp, sizeof(*mmp_cmp))) { + retval = EXT2_ET_MMP_CHANGE_ABORT; + goto mmp_error; + } + + mmp_cmp->mmp_seq = EXT4_MMP_SEQ_CLEAN; + retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_cmp); + +mmp_error: + if (fs->mmp_fd > 0) { + close(fs->mmp_fd); + fs->mmp_fd = -1; + } + + return retval; +#else + if (!ext2fs_has_feature_mmp(fs->super) || + !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP)) + return 0; + + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +#define EXT2_MIN_MMP_UPDATE_INTERVAL 60 + +/* + * Update the on-disk mmp buffer, after checking that it hasn't been changed. + */ +errcode_t ext2fs_mmp_update2(ext2_filsys fs, int immediately) +{ +#ifdef CONFIG_MMP + struct mmp_struct *mmp, *mmp_cmp; + struct timeval tv; + errcode_t retval = 0; + + if (!ext2fs_has_feature_mmp(fs->super) || + !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP)) + return 0; + + gettimeofday(&tv, 0); + if (!immediately && + tv.tv_sec - fs->mmp_last_written < EXT2_MIN_MMP_UPDATE_INTERVAL) + return 0; + + retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, NULL); + if (retval) + goto mmp_error; + + mmp = fs->mmp_buf; + mmp_cmp = fs->mmp_cmp; + + if (memcmp(mmp, mmp_cmp, sizeof(*mmp_cmp))) + return EXT2_ET_MMP_CHANGE_ABORT; + + mmp->mmp_time = tv.tv_sec; + mmp->mmp_seq = EXT4_MMP_SEQ_FSCK; + retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf); + +mmp_error: + return retval; +#else + if (!ext2fs_has_feature_mmp(fs->super) || + !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP)) + return 0; + + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} +#if __GNUC_PREREQ (4, 6) +#pragma GCC diagnostic pop +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/namei.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/namei.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,227 @@ +/* + * namei.c --- ext2fs directory lookup operations + * + * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +/* #define NAMEI_DEBUG */ + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base, + const char *pathname, size_t pathlen, int follow, + int link_count, char *buf, ext2_ino_t *res_inode); + +static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir, + ext2_ino_t inode, int link_count, + char *buf, ext2_ino_t *res_inode) +{ + char *pathname; + char *buffer = 0; + errcode_t retval; + struct ext2_inode ei; + blk64_t blk; + +#ifdef NAMEI_DEBUG + printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n", + root, dir, inode, link_count); + +#endif + retval = ext2fs_read_inode (fs, inode, &ei); + if (retval) return retval; + if (!LINUX_S_ISLNK (ei.i_mode)) { + *res_inode = inode; + return 0; + } + if (link_count++ >= EXT2FS_MAX_NESTED_LINKS) + return EXT2_ET_SYMLINK_LOOP; + + if (ext2fs_is_fast_symlink(&ei)) + pathname = (char *)&(ei.i_block[0]); + else if (ei.i_flags & EXT4_INLINE_DATA_FL) { + retval = ext2fs_get_memzero(ei.i_size, &buffer); + if (retval) + return retval; + + retval = ext2fs_inline_data_get(fs, inode, + &ei, buffer, NULL); + if (retval) { + ext2fs_free_mem(&buffer); + return retval; + } + pathname = buffer; + } else { + retval = ext2fs_bmap2(fs, inode, &ei, NULL, 0, 0, NULL, &blk); + if (retval) + return retval; + + retval = ext2fs_get_mem(fs->blocksize, &buffer); + if (retval) + return retval; + + retval = io_channel_read_blk64(fs->io, blk, 1, buffer); + if (retval) { + ext2fs_free_mem(&buffer); + return retval; + } + pathname = buffer; + } + + retval = open_namei(fs, root, dir, pathname, ei.i_size, 1, + link_count, buf, res_inode); + if (buffer) + ext2fs_free_mem(&buffer); + return retval; +} + +/* + * This routine interprets a pathname in the context of the current + * directory and the root directory, and returns the inode of the + * containing directory, and a pointer to the filename of the file + * (pointing into the pathname) and the length of the filename. + */ +static errcode_t dir_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir, + const char *pathname, int pathlen, + int link_count, char *buf, + const char **name, int *namelen, + ext2_ino_t *res_inode) +{ + char c; + const char *thisname; + int len; + ext2_ino_t inode; + errcode_t retval; + + if ((c = *pathname) == '/') { + dir = root; + pathname++; + pathlen--; + } + while (1) { + thisname = pathname; + for (len=0; --pathlen >= 0;len++) { + c = *(pathname++); + if (c == '/') + break; + } + if (pathlen < 0) + break; + retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode); + if (retval) return retval; + retval = follow_link (fs, root, dir, inode, + link_count, buf, &dir); + if (retval) return retval; + } + *name = thisname; + *namelen = len; + *res_inode = dir; + return 0; +} + +static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base, + const char *pathname, size_t pathlen, int follow, + int link_count, char *buf, ext2_ino_t *res_inode) +{ + const char *base_name; + int namelen; + ext2_ino_t dir, inode; + errcode_t retval; + +#ifdef NAMEI_DEBUG + printf("open_namei: root=%lu, dir=%lu, path=%.*s, lc=%d\n", + root, base, pathlen, pathname, link_count); +#endif + retval = dir_namei(fs, root, base, pathname, pathlen, + link_count, buf, &base_name, &namelen, &dir); + if (retval) return retval; + if (!namelen) { /* special case: '/usr/' etc */ + *res_inode=dir; + return 0; + } + retval = ext2fs_lookup (fs, dir, base_name, namelen, buf, &inode); + if (retval) + return retval; + if (follow) { + retval = follow_link(fs, root, dir, inode, link_count, + buf, &inode); + if (retval) + return retval; + } +#ifdef NAMEI_DEBUG + printf("open_namei: (link_count=%d) returns %lu\n", + link_count, inode); +#endif + *res_inode = inode; + return 0; +} + +errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, + const char *name, ext2_ino_t *inode) +{ + char *buf; + errcode_t retval; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + retval = ext2fs_get_mem(fs->blocksize, &buf); + if (retval) + return retval; + + retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0, + buf, inode); + + ext2fs_free_mem(&buf); + return retval; +} + +errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, + const char *name, ext2_ino_t *inode) +{ + char *buf; + errcode_t retval; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + retval = ext2fs_get_mem(fs->blocksize, &buf); + if (retval) + return retval; + + retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0, + buf, inode); + + ext2fs_free_mem(&buf); + return retval; +} + +errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, + ext2_ino_t inode, ext2_ino_t *res_inode) +{ + char *buf; + errcode_t retval; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + retval = ext2fs_get_mem(fs->blocksize, &buf); + if (retval) + return retval; + + retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode); + + ext2fs_free_mem(&buf); + return retval; +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/native.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/native.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,28 @@ +/* + * native.c --- returns the ext2_flag for a native byte order + * + * Copyright (C) 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include + +#include "ext2_fs.h" +#include "ext2fs.h" + +int ext2fs_native_flag(void) +{ +#ifdef WORDS_BIGENDIAN + return EXT2_FLAG_SWAP_BYTES; +#else + return 0; +#endif +} + + + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/newdir.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/newdir.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,126 @@ +/* + * newdir.c --- create a new directory block + * + * Copyright (C) 1994, 1995 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +#ifndef EXT2_FT_DIR +#define EXT2_FT_DIR 2 +#endif + +/* + * Create new directory block + */ +errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino, + ext2_ino_t parent_ino, char **block) +{ + struct ext2_dir_entry *dir = NULL; + errcode_t retval; + char *buf; + int rec_len; + int filetype = 0; + struct ext2_dir_entry_tail *t; + int csum_size = 0; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + retval = ext2fs_get_mem(fs->blocksize, &buf); + if (retval) + return retval; + memset(buf, 0, fs->blocksize); + dir = (struct ext2_dir_entry *) buf; + + if (ext2fs_has_feature_metadata_csum(fs->super)) + csum_size = sizeof(struct ext2_dir_entry_tail); + + retval = ext2fs_set_rec_len(fs, fs->blocksize - csum_size, dir); + if (retval) { + ext2fs_free_mem(&buf); + return retval; + } + + if (dir_ino) { + if (ext2fs_has_feature_filetype(fs->super)) + filetype = EXT2_FT_DIR; + /* + * Set up entry for '.' + */ + dir->inode = dir_ino; + ext2fs_dirent_set_name_len(dir, 1); + ext2fs_dirent_set_file_type(dir, filetype); + dir->name[0] = '.'; + rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1); + dir->rec_len = EXT2_DIR_REC_LEN(1); + + /* + * Set up entry for '..' + */ + dir = (struct ext2_dir_entry *) (buf + dir->rec_len); + retval = ext2fs_set_rec_len(fs, rec_len, dir); + if (retval) { + ext2fs_free_mem(&buf); + return retval; + } + dir->inode = parent_ino; + ext2fs_dirent_set_name_len(dir, 2); + ext2fs_dirent_set_file_type(dir, filetype); + dir->name[0] = '.'; + dir->name[1] = '.'; + + } + + if (csum_size) { + t = EXT2_DIRENT_TAIL(buf, fs->blocksize); + ext2fs_initialize_dirent_tail(fs, t); + } + *block = buf; + return 0; +} + +/* + * Create new directory on inline data + */ +errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs, + ext2_ino_t dir_ino EXT2FS_ATTR((unused)), + ext2_ino_t parent_ino, __u32 *iblock) +{ + struct ext2_dir_entry *dir = NULL; + errcode_t retval; + int rec_len; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + iblock[0] = ext2fs_cpu_to_le32(parent_ino); + + dir = (struct ext2_dir_entry *)((char *)iblock + + EXT4_INLINE_DATA_DOTDOT_SIZE); + dir->inode = 0; + rec_len = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE; + retval = ext2fs_set_rec_len(fs, rec_len, dir); + if (retval) + goto errout; + +#ifdef WORDS_BIGENDIAN + retval = ext2fs_dirent_swab_out2(fs, (char *)dir, rec_len, 0); + if (retval) + goto errout; +#endif + +errout: + return retval; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/openfs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/openfs.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,562 @@ +/* + * openfs.c --- open an ext2 filesystem + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "ext2_fs.h" + + +#include "ext2fs.h" +#include "e2image.h" + +blk64_t ext2fs_descriptor_block_loc2(ext2_filsys fs, blk64_t group_block, + dgrp_t i) +{ + int bg; + int has_super = 0, group_zero_adjust = 0; + blk64_t ret_blk; + + /* + * On a bigalloc FS with 1K blocks, block 0 is reserved for non-ext4 + * stuff, so adjust for that if we're being asked for group 0. + */ + if (i == 0 && fs->blocksize == 1024 && EXT2FS_CLUSTER_RATIO(fs) > 1) + group_zero_adjust = 1; + + if (!ext2fs_has_feature_meta_bg(fs->super) || + (i < fs->super->s_first_meta_bg)) + return group_block + i + 1 + group_zero_adjust; + + bg = EXT2_DESC_PER_BLOCK(fs->super) * i; + if (ext2fs_bg_has_super(fs, bg)) + has_super = 1; + ret_blk = ext2fs_group_first_block2(fs, bg); + /* + * If group_block is not the normal value, we're trying to use + * the backup group descriptors and superblock --- so use the + * alternate location of the second block group in the + * metablock group. Ideally we should be testing each bg + * descriptor block individually for correctness, but we don't + * have the infrastructure in place to do that. + */ + if (group_block != fs->super->s_first_data_block && + ((ret_blk + has_super + fs->super->s_blocks_per_group) < + ext2fs_blocks_count(fs->super))) { + ret_blk += fs->super->s_blocks_per_group; + + /* + * If we're going to jump forward a block group, make sure + * that we adjust has_super to account for the next group's + * backup superblock (or lack thereof). + */ + if (ext2fs_bg_has_super(fs, bg + 1)) + has_super = 1; + else + has_super = 0; + } + return ret_blk + has_super + group_zero_adjust; +} + +blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i) +{ + return ext2fs_descriptor_block_loc2(fs, group_block, i); +} + +errcode_t ext2fs_open(const char *name, int flags, int superblock, + unsigned int block_size, io_manager manager, + ext2_filsys *ret_fs) +{ + return ext2fs_open2(name, 0, flags, superblock, block_size, + manager, ret_fs); +} + +static void block_sha_map_free_entry(void *data) +{ + free(data); + return; +} + +/* + * Note: if superblock is non-zero, block-size must also be non-zero. + * Superblock and block_size can be zero to use the default size. + * + * Valid flags for ext2fs_open() + * + * EXT2_FLAG_RW - Open the filesystem for read/write. + * EXT2_FLAG_FORCE - Open the filesystem even if some of the + * features aren't supported. + * EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device + * EXT2_FLAG_SKIP_MMP - Open without multi-mount protection check. + * EXT2_FLAG_64BITS - Allow 64-bit bitfields (needed for large + * filesystems) + */ +errcode_t ext2fs_open2(const char *name, const char *io_options, + int flags, int superblock, + unsigned int block_size, io_manager manager, + ext2_filsys *ret_fs) +{ + ext2_filsys fs; + errcode_t retval; + unsigned long i, first_meta_bg; + __u32 features; + unsigned int blocks_per_group, io_flags; + blk64_t group_block, blk; + char *dest, *cp; + int group_zero_adjust = 0; + unsigned int inode_size; + __u64 groups_cnt; +#ifdef WORDS_BIGENDIAN + unsigned int groups_per_block; + struct ext2_group_desc *gdp; + int j; +#endif + char *time_env; + + EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER); + + retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs); + if (retval) + return retval; + + memset(fs, 0, sizeof(struct struct_ext2_filsys)); + fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS; + fs->flags = flags; + /* don't overwrite sb backups unless flag is explicitly cleared */ + fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; + fs->umask = 022; + + time_env = getenv("E2FSPROGS_FAKE_TIME"); + if (time_env) + fs->now = strtoul(time_env, NULL, 0); + + retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name); + if (retval) + goto cleanup; + strcpy(fs->device_name, name); + cp = strchr(fs->device_name, '?'); + if (!io_options && cp) { + *cp++ = 0; + io_options = cp; + } + + io_flags = 0; + if (flags & EXT2_FLAG_RW) + io_flags |= IO_FLAG_RW; + if (flags & EXT2_FLAG_EXCLUSIVE) + io_flags |= IO_FLAG_EXCLUSIVE; + if (flags & EXT2_FLAG_DIRECT_IO) + io_flags |= IO_FLAG_DIRECT_IO; + retval = manager->open(fs->device_name, io_flags, &fs->io); + if (retval) + goto cleanup; + if (io_options && + (retval = io_channel_set_options(fs->io, io_options))) + goto cleanup; + fs->image_io = fs->io; + fs->io->app_data = fs; + retval = io_channel_alloc_buf(fs->io, -SUPERBLOCK_SIZE, &fs->super); + if (retval) + goto cleanup; + if (flags & EXT2_FLAG_IMAGE_FILE) { + retval = ext2fs_get_mem(sizeof(struct ext2_image_hdr), + &fs->image_header); + if (retval) + goto cleanup; + retval = io_channel_read_blk(fs->io, 0, + -(int)sizeof(struct ext2_image_hdr), + fs->image_header); + if (retval) + goto cleanup; + if (ext2fs_le32_to_cpu(fs->image_header->magic_number) != EXT2_ET_MAGIC_E2IMAGE) + return EXT2_ET_MAGIC_E2IMAGE; + superblock = 1; + block_size = ext2fs_le32_to_cpu(fs->image_header->fs_blocksize); + } + + /* + * If the user specifies a specific block # for the + * superblock, then he/she must also specify the block size! + * Otherwise, read the master superblock located at offset + * SUPERBLOCK_OFFSET from the start of the partition. + * + * Note: we only save a backup copy of the superblock if we + * are reading the superblock from the primary superblock location. + */ + if (superblock) { + if (!block_size) { + retval = EXT2_ET_INVALID_ARGUMENT; + goto cleanup; + } + io_channel_set_blksize(fs->io, block_size); + group_block = superblock; + fs->orig_super = 0; + } else { + io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET); + superblock = 1; + group_block = 0; + retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super); + if (retval) + goto cleanup; + } + retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE, + fs->super); + if (retval) + goto cleanup; + if (fs->orig_super) + memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE); + + if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)) { + retval = 0; + if (!ext2fs_verify_csum_type(fs, fs->super)) + retval = EXT2_ET_UNKNOWN_CSUM; + if (!ext2fs_superblock_csum_verify(fs, fs->super)) + retval = EXT2_ET_SB_CSUM_INVALID; + } + +#ifdef WORDS_BIGENDIAN + fs->flags |= EXT2_FLAG_SWAP_BYTES; + ext2fs_swap_super(fs->super); +#else + if (fs->flags & EXT2_FLAG_SWAP_BYTES) { + retval = EXT2_ET_UNIMPLEMENTED; + goto cleanup; + } +#endif + + if (fs->super->s_magic != EXT2_SUPER_MAGIC) + retval = EXT2_ET_BAD_MAGIC; + if (retval) + goto cleanup; + + if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) { + retval = EXT2_ET_REV_TOO_HIGH; + goto cleanup; + } + + /* + * Check for feature set incompatibility + */ + if (!(flags & EXT2_FLAG_FORCE)) { + features = fs->super->s_feature_incompat; +#ifdef EXT2_LIB_SOFTSUPP_INCOMPAT + if (flags & EXT2_FLAG_SOFTSUPP_FEATURES) + features &= ~EXT2_LIB_SOFTSUPP_INCOMPAT; +#endif + if (features & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) { + retval = EXT2_ET_UNSUPP_FEATURE; + goto cleanup; + } + + features = fs->super->s_feature_ro_compat; +#ifdef EXT2_LIB_SOFTSUPP_RO_COMPAT + if (flags & EXT2_FLAG_SOFTSUPP_FEATURES) + features &= ~EXT2_LIB_SOFTSUPP_RO_COMPAT; +#endif + if ((flags & EXT2_FLAG_RW) && + (features & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) { + retval = EXT2_ET_RO_UNSUPP_FEATURE; + goto cleanup; + } + + if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) && + ext2fs_has_feature_journal_dev(fs->super)) { + retval = EXT2_ET_UNSUPP_FEATURE; + goto cleanup; + } + } + + if (fs->super->s_log_block_size > + (unsigned) (EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE)) { + retval = EXT2_ET_CORRUPT_SUPERBLOCK; + goto cleanup; + } + + /* + * bigalloc requires cluster-aware bitfield operations, which at the + * moment means we need EXT2_FLAG_64BITS. + */ + if (ext2fs_has_feature_bigalloc(fs->super) && + !(flags & EXT2_FLAG_64BITS)) { + retval = EXT2_ET_CANT_USE_LEGACY_BITMAPS; + goto cleanup; + } + + if (!ext2fs_has_feature_bigalloc(fs->super) && + (fs->super->s_log_block_size != fs->super->s_log_cluster_size)) { + retval = EXT2_ET_CORRUPT_SUPERBLOCK; + goto cleanup; + } + fs->fragsize = fs->blocksize = EXT2_BLOCK_SIZE(fs->super); + inode_size = EXT2_INODE_SIZE(fs->super); + if ((inode_size < EXT2_GOOD_OLD_INODE_SIZE) || + (inode_size > fs->blocksize) || + (inode_size & (inode_size - 1))) { + retval = EXT2_ET_CORRUPT_SUPERBLOCK; + goto cleanup; + } + + /* Enforce the block group descriptor size */ + if (ext2fs_has_feature_64bit(fs->super)) { + if (fs->super->s_desc_size < EXT2_MIN_DESC_SIZE_64BIT) { + retval = EXT2_ET_BAD_DESC_SIZE; + goto cleanup; + } + } + + fs->cluster_ratio_bits = fs->super->s_log_cluster_size - + fs->super->s_log_block_size; + if (EXT2_BLOCKS_PER_GROUP(fs->super) != + EXT2_CLUSTERS_PER_GROUP(fs->super) << fs->cluster_ratio_bits) { + retval = EXT2_ET_CORRUPT_SUPERBLOCK; + goto cleanup; + } + fs->inode_blocks_per_group = ((EXT2_INODES_PER_GROUP(fs->super) * + EXT2_INODE_SIZE(fs->super) + + EXT2_BLOCK_SIZE(fs->super) - 1) / + EXT2_BLOCK_SIZE(fs->super)); + if (block_size) { + if (block_size != fs->blocksize) { + retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE; + goto cleanup; + } + } + /* + * Set the blocksize to the filesystem's blocksize. + */ + io_channel_set_blksize(fs->io, fs->blocksize); + + /* + * If this is an external journal device, don't try to read + * the group descriptors, because they're not there. + */ + if (ext2fs_has_feature_journal_dev(fs->super)) { + fs->group_desc_count = 0; + *ret_fs = fs; + return 0; + } + + if (EXT2_INODES_PER_GROUP(fs->super) == 0) { + retval = EXT2_ET_CORRUPT_SUPERBLOCK; + goto cleanup; + } + /* Precompute the FS UUID to seed other checksums */ + ext2fs_init_csum_seed(fs); + + /* + * Read group descriptors + */ + blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super); + if (blocks_per_group == 0 || + blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) || + fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super) || + EXT2_DESC_PER_BLOCK(fs->super) == 0 || + fs->super->s_first_data_block >= ext2fs_blocks_count(fs->super)) { + retval = EXT2_ET_CORRUPT_SUPERBLOCK; + goto cleanup; + } + groups_cnt = ext2fs_div64_ceil(ext2fs_blocks_count(fs->super) - + fs->super->s_first_data_block, + blocks_per_group); + if (groups_cnt >> 32) { + retval = EXT2_ET_CORRUPT_SUPERBLOCK; + goto cleanup; + } + fs->group_desc_count = groups_cnt; + if (!(flags & EXT2_FLAG_IGNORE_SB_ERRORS) && + (__u64)fs->group_desc_count * EXT2_INODES_PER_GROUP(fs->super) != + fs->super->s_inodes_count) { + retval = EXT2_ET_CORRUPT_SUPERBLOCK; + goto cleanup; + } + fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count, + EXT2_DESC_PER_BLOCK(fs->super)); + retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize, + &fs->group_desc); + if (retval) + goto cleanup; + if (!group_block) + group_block = fs->super->s_first_data_block; + /* + * On a FS with a 1K blocksize, block 0 is reserved for bootloaders + * so we must increment block numbers to any group 0 items. + * + * However, we cannot touch group_block directly because in the meta_bg + * case, the ext2fs_descriptor_block_loc2() function will interpret + * group_block != s_first_data_block to mean that we want to access the + * backup group descriptors. This is not what we want if the caller + * set superblock == 0 (i.e. auto-detect the superblock), which is + * what's going on here. + */ + if (group_block == 0 && fs->blocksize == 1024) + group_zero_adjust = 1; + dest = (char *) fs->group_desc; +#ifdef WORDS_BIGENDIAN + groups_per_block = EXT2_DESC_PER_BLOCK(fs->super); +#endif + if (ext2fs_has_feature_meta_bg(fs->super) && + !(flags & EXT2_FLAG_IMAGE_FILE)) { + first_meta_bg = fs->super->s_first_meta_bg; + if (first_meta_bg > fs->desc_blocks) + first_meta_bg = fs->desc_blocks; + } else + first_meta_bg = fs->desc_blocks; + if (first_meta_bg) { + retval = io_channel_read_blk(fs->io, group_block + + group_zero_adjust + 1, + first_meta_bg, dest); + if (retval) + goto cleanup; +#ifdef WORDS_BIGENDIAN + gdp = (struct ext2_group_desc *) dest; + for (j=0; j < groups_per_block*first_meta_bg; j++) { + gdp = ext2fs_group_desc(fs, fs->group_desc, j); + ext2fs_swap_group_desc2(fs, gdp); + } +#endif + dest += fs->blocksize*first_meta_bg; + } + + for (i = first_meta_bg ; i < fs->desc_blocks; i++) { + blk = ext2fs_descriptor_block_loc2(fs, group_block, i); + io_channel_cache_readahead(fs->io, blk, 1); + } + + for (i=first_meta_bg ; i < fs->desc_blocks; i++) { + blk = ext2fs_descriptor_block_loc2(fs, group_block, i); + retval = io_channel_read_blk64(fs->io, blk, 1, dest); + if (retval) + goto cleanup; +#ifdef WORDS_BIGENDIAN + for (j=0; j < groups_per_block; j++) { + gdp = ext2fs_group_desc(fs, fs->group_desc, + i * groups_per_block + j); + ext2fs_swap_group_desc2(fs, gdp); + } +#endif + dest += fs->blocksize; + } + + fs->stride = fs->super->s_raid_stride; + + /* + * If recovery is from backup superblock, Clear _UNININT flags & + * reset bg_itable_unused to zero + */ + if (superblock > 1 && ext2fs_has_group_desc_csum(fs)) { + dgrp_t group; + + for (group = 0; group < fs->group_desc_count; group++) { + ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); + ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT); + ext2fs_bg_itable_unused_set(fs, group, 0); + /* The checksum will be reset later, but fix it here + * anyway to avoid printing a lot of spurious errors. */ + ext2fs_group_desc_csum_set(fs, group); + } + if (fs->flags & EXT2_FLAG_RW) + ext2fs_mark_super_dirty(fs); + } + + if (ext2fs_has_feature_mmp(fs->super) && + !(flags & EXT2_FLAG_SKIP_MMP) && + (flags & (EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE))) { + retval = ext2fs_mmp_start(fs); + if (retval) { + fs->flags |= EXT2_FLAG_SKIP_MMP; /* just do cleanup */ + ext2fs_mmp_stop(fs); + goto cleanup; + } + } + + if (fs->flags & EXT2_FLAG_SHARE_DUP) { + fs->block_sha_map = ext2fs_hashmap_create(ext2fs_djb2_hash, + block_sha_map_free_entry, 4096); + if (!fs->block_sha_map) { + retval = EXT2_ET_NO_MEMORY; + goto cleanup; + } + ext2fs_set_feature_shared_blocks(fs->super); + } + + fs->flags &= ~EXT2_FLAG_NOFREE_ON_ERROR; + *ret_fs = fs; + + return 0; +cleanup: + if (!(flags & EXT2_FLAG_NOFREE_ON_ERROR)) { + ext2fs_free(fs); + fs = NULL; + } + *ret_fs = fs; + return retval; +} + +/* + * Set/get the filesystem data I/O channel. + * + * These functions are only valid if EXT2_FLAG_IMAGE_FILE is true. + */ +errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io) +{ + if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0) + return EXT2_ET_NOT_IMAGE_FILE; + if (old_io) { + *old_io = (fs->image_io == fs->io) ? 0 : fs->io; + } + return 0; +} + +errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io) +{ + if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0) + return EXT2_ET_NOT_IMAGE_FILE; + fs->io = new_io ? new_io : fs->image_io; + return 0; +} + +errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io) +{ + errcode_t err; + + if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0) + return EXT2_ET_NOT_IMAGE_FILE; + err = io_channel_set_blksize(new_io, fs->blocksize); + if (err) + return err; + if ((new_io == fs->image_io) || (new_io == fs->io)) + return 0; + if ((fs->image_io != fs->io) && + fs->image_io) + io_channel_close(fs->image_io); + if (fs->io) + io_channel_close(fs->io); + fs->io = fs->image_io = new_io; + fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_RW | + EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY; + fs->flags &= ~EXT2_FLAG_IMAGE_FILE; + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/progress.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/progress.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,103 @@ +/* + * progress.c - Numeric progress meter + * + * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + * 2003, 2004, 2005 by Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "config.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +#include + +static char spaces[80], backspaces[80]; +static time_t last_update; + +struct ext2fs_progress_ops ext2fs_numeric_progress_ops = { + .init = ext2fs_numeric_progress_init, + .update = ext2fs_numeric_progress_update, + .close = ext2fs_numeric_progress_close, +}; + +static int int_log10(unsigned int arg) +{ + int l; + + for (l=0; arg ; l++) + arg = arg / 10; + return l; +} + +void ext2fs_numeric_progress_init(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + const char *label, __u64 max) +{ + /* + * The PRINT_PROGRESS flag turns on or off ALL + * progress-related messages, whereas the SKIP_PROGRESS + * environment variable prints the start and end messages but + * not the numeric countdown in the middle. + */ + if (!(fs->flags & EXT2_FLAG_PRINT_PROGRESS)) + return; + + memset(spaces, ' ', sizeof(spaces)-1); + spaces[sizeof(spaces)-1] = 0; + memset(backspaces, '\b', sizeof(backspaces)-1); + backspaces[sizeof(backspaces)-1] = 0; + + memset(progress, 0, sizeof(*progress)); + if (getenv("E2FSPROGS_SKIP_PROGRESS")) + progress->skip_progress++; + + + /* + * Figure out how many digits we need + */ + progress->max = max; + progress->log_max = int_log10(max); + + if (label) { + fputs(label, stdout); + fflush(stdout); + } + last_update = 0; +} + +void ext2fs_numeric_progress_update(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + __u64 val) +{ + time_t now; + + if (!(fs->flags & EXT2_FLAG_PRINT_PROGRESS)) + return; + if (progress->skip_progress) + return; + now = time(0); + if (now == last_update) + return; + last_update = now; + + printf("%*llu/%*llu", progress->log_max, val, + progress->log_max, progress->max); + fprintf(stdout, "%.*s", (2*progress->log_max)+1, backspaces); +} + +void ext2fs_numeric_progress_close(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + const char *message) +{ + if (!(fs->flags & EXT2_FLAG_PRINT_PROGRESS)) + return; + fprintf(stdout, "%.*s", (2*progress->log_max)+1, spaces); + fprintf(stdout, "%.*s", (2*progress->log_max)+1, backspaces); + if (message) + fputs(message, stdout); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/punch.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/punch.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,509 @@ +/* + * punch.c --- deallocate blocks allocated to an inode + * + * Copyright (C) 2010 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +#undef PUNCH_DEBUG + +/* + * This function returns 1 if the specified block is all zeros + */ +static int check_zero_block(char *buf, int blocksize) +{ + char *cp = buf; + int left = blocksize; + + while (left > 0) { + if (*cp++) + return 0; + left--; + } + return 1; +} + +/* + * This clever recursive function handles i_blocks[] as well as + * indirect, double indirect, and triple indirect blocks. It iterates + * over the entries in the i_blocks array or indirect blocks, and for + * each one, will recursively handle any indirect blocks and then + * frees and deallocates the blocks. + */ +static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode, + char *block_buf, blk_t *p, int level, + blk64_t start, blk64_t count, int max) +{ + errcode_t retval; + blk_t b; + int i; + blk64_t offset, incr; + int freed = 0; + +#ifdef PUNCH_DEBUG + printf("Entering ind_punch, level %d, start %llu, count %llu, " + "max %d\n", level, start, count, max); +#endif + incr = 1ULL << ((EXT2_BLOCK_SIZE_BITS(fs->super) - 2) * level); + for (i = 0, offset = 0; i < max; i++, p++, offset += incr) { + if (offset >= start + count) + break; + if (*p == 0 || (offset+incr) <= start) + continue; + b = *p; + if (level > 0) { + blk_t start2; +#ifdef PUNCH_DEBUG + printf("Reading indirect block %u\n", b); +#endif + retval = ext2fs_read_ind_block(fs, b, block_buf); + if (retval) + return retval; + start2 = (start > offset) ? start - offset : 0; + retval = ind_punch(fs, inode, block_buf + fs->blocksize, + (blk_t *) block_buf, level - 1, + start2, count - offset, + fs->blocksize >> 2); + if (retval) + return retval; + retval = ext2fs_write_ind_block(fs, b, block_buf); + if (retval) + return retval; + if (!check_zero_block(block_buf, fs->blocksize)) + continue; + } +#ifdef PUNCH_DEBUG + printf("Freeing block %u (offset %llu)\n", b, offset); +#endif + ext2fs_block_alloc_stats(fs, b, -1); + *p = 0; + freed++; + } +#ifdef PUNCH_DEBUG + printf("Freed %d blocks\n", freed); +#endif + return ext2fs_iblk_sub_blocks(fs, inode, freed); +} + +#define BLK_T_MAX ((blk_t)~0ULL) +static errcode_t ext2fs_punch_ind(ext2_filsys fs, struct ext2_inode *inode, + char *block_buf, blk64_t start, blk64_t end) +{ + errcode_t retval; + char *buf = 0; + int level; + int num = EXT2_NDIR_BLOCKS; + blk_t *bp = inode->i_block; + blk_t addr_per_block; + blk64_t max = EXT2_NDIR_BLOCKS; + blk_t count; + + /* Check start/end don't overflow the 2^32-1 indirect block limit */ + if (start > BLK_T_MAX) + return 0; + if (end >= BLK_T_MAX || end - start + 1 >= BLK_T_MAX) + count = BLK_T_MAX - start; + else + count = end - start + 1; + + if (!block_buf) { + retval = ext2fs_get_array(3, fs->blocksize, &buf); + if (retval) + return retval; + block_buf = buf; + } + + addr_per_block = (blk_t)fs->blocksize >> 2; + + for (level = 0; level < 4; level++, max *= (blk64_t)addr_per_block) { +#ifdef PUNCH_DEBUG + printf("Main loop level %d, start %llu count %u " + "max %llu num %d\n", level, start, count, max, num); +#endif + if (start < max) { + retval = ind_punch(fs, inode, block_buf, bp, level, + start, count, num); + if (retval) + goto errout; + if (count > max) + count -= max - start; + else + break; + start = 0; + } else + start -= max; + bp += num; + if (level == 0) { + num = 1; + max = 1; + } + } + retval = 0; +errout: + if (buf) + ext2fs_free_mem(&buf); + return retval; +} +#undef BLK_T_MAX + +#ifdef PUNCH_DEBUG + +#define dbg_printf(f, a...) printf(f, ## a) + +static void dbg_print_extent(char *desc, struct ext2fs_extent *extent) +{ + if (desc) + printf("%s: ", desc); + printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ", + extent->e_lblk, extent->e_lblk + extent->e_len - 1, + extent->e_len, extent->e_pblk); + if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF) + fputs("LEAF ", stdout); + if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) + fputs("UNINIT ", stdout); + if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) + fputs("2ND_VISIT ", stdout); + if (!extent->e_flags) + fputs("(none)", stdout); + fputc('\n', stdout); + +} +#else +#define dbg_print_extent(desc, ex) do { } while (0) +#define dbg_printf(f, a...) do { } while (0) +#endif + +/* Free a range of blocks, respecting cluster boundaries */ +static errcode_t punch_extent_blocks(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + blk64_t lfree_start, blk64_t free_start, + __u32 free_count, int *freed) +{ + blk64_t pblk; + int freed_now = 0; + __u32 cluster_freed; + errcode_t retval = 0; + + /* No bigalloc? Just free each block. */ + if (EXT2FS_CLUSTER_RATIO(fs) == 1) { + *freed += free_count; + while (free_count-- > 0) + ext2fs_block_alloc_stats2(fs, free_start++, -1); + return retval; + } + + /* + * Try to free up to the next cluster boundary. We assume that all + * blocks in a logical cluster map to blocks from the same physical + * cluster, and that the offsets within the [pl]clusters match. + */ + if (free_start & EXT2FS_CLUSTER_MASK(fs)) { + retval = ext2fs_map_cluster_block(fs, ino, inode, + lfree_start, &pblk); + if (retval) + goto errout; + if (!pblk) { + ext2fs_block_alloc_stats2(fs, free_start, -1); + freed_now++; + } + cluster_freed = EXT2FS_CLUSTER_RATIO(fs) - + (free_start & EXT2FS_CLUSTER_MASK(fs)); + if (cluster_freed > free_count) + cluster_freed = free_count; + free_count -= cluster_freed; + free_start += cluster_freed; + lfree_start += cluster_freed; + } + + /* Free whole clusters from the middle of the range. */ + while (free_count > 0 && free_count >= (unsigned) EXT2FS_CLUSTER_RATIO(fs)) { + ext2fs_block_alloc_stats2(fs, free_start, -1); + freed_now++; + cluster_freed = EXT2FS_CLUSTER_RATIO(fs); + free_count -= cluster_freed; + free_start += cluster_freed; + lfree_start += cluster_freed; + } + + /* Try to free the last cluster. */ + if (free_count > 0) { + retval = ext2fs_map_cluster_block(fs, ino, inode, + lfree_start, &pblk); + if (retval) + goto errout; + if (!pblk) { + ext2fs_block_alloc_stats2(fs, free_start, -1); + freed_now++; + } + } + +errout: + *freed += freed_now; + return retval; +} + +static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + blk64_t start, blk64_t end) +{ + ext2_extent_handle_t handle = 0; + struct ext2fs_extent extent; + errcode_t retval; + blk64_t free_start, next, lfree_start; + __u32 free_count, newlen; + int freed = 0; + int op; + + retval = ext2fs_extent_open2(fs, ino, inode, &handle); + if (retval) + return retval; + /* + * Find the extent closest to the start of the punch range. We don't + * check the return value because _goto() sets the current node to the + * next-lowest extent if 'start' is in a hole, and doesn't set a + * current node if there was a real error reading the extent tree. + * In that case, _get() will error out. + * + * Note: If _get() returns 'no current node', that simply means that + * there aren't any blocks mapped past this point in the file, so we're + * done. + */ + ext2fs_extent_goto(handle, start); + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); + if (retval == EXT2_ET_NO_CURRENT_NODE) { + retval = 0; + goto errout; + } else if (retval) + goto errout; + while (1) { + op = EXT2_EXTENT_NEXT_LEAF; + dbg_print_extent("main loop", &extent); + next = extent.e_lblk + extent.e_len; + dbg_printf("start %llu, end %llu, next %llu\n", + (unsigned long long) start, + (unsigned long long) end, + (unsigned long long) next); + if (start <= extent.e_lblk) { + /* + * Have we iterated past the end of the punch region? + * If so, we can stop. + */ + if (end < extent.e_lblk) + break; + dbg_printf("Case #%d\n", 1); + /* Start of deleted region before extent; + adjust beginning of extent */ + free_start = extent.e_pblk; + lfree_start = extent.e_lblk; + if (next > end) + free_count = end - extent.e_lblk + 1; + else + free_count = extent.e_len; + extent.e_len -= free_count; + extent.e_lblk += free_count; + extent.e_pblk += free_count; + } else if (end >= next-1) { + /* + * Is the punch region beyond this extent? This can + * happen if start is already inside a hole. Try to + * advance to the next extent if this is the case. + */ + if (start >= next) + goto next_extent; + /* End of deleted region after extent; + adjust end of extent */ + dbg_printf("Case #%d\n", 2); + newlen = start - extent.e_lblk; + free_start = extent.e_pblk + newlen; + lfree_start = extent.e_lblk + newlen; + free_count = extent.e_len - newlen; + extent.e_len = newlen; + } else { + struct ext2fs_extent newex; + + dbg_printf("Case #%d\n", 3); + /* The hard case; we need to split the extent */ + newex.e_pblk = extent.e_pblk + + (end + 1 - extent.e_lblk); + newex.e_lblk = end + 1; + newex.e_len = next - end - 1; + newex.e_flags = extent.e_flags; + + extent.e_len = start - extent.e_lblk; + free_start = extent.e_pblk + extent.e_len; + lfree_start = extent.e_lblk + extent.e_len; + free_count = end - start + 1; + + dbg_print_extent("inserting", &newex); + retval = ext2fs_extent_insert(handle, + EXT2_EXTENT_INSERT_AFTER, &newex); + if (retval) + goto errout; + retval = ext2fs_extent_fix_parents(handle); + if (retval) + goto errout; + /* + * Now pointing at inserted extent; so go back. + * + * We cannot use EXT2_EXTENT_PREV to go back; note the + * subtlety in the comment for fix_parents(). + */ + retval = ext2fs_extent_goto(handle, extent.e_lblk); + if (retval) + goto errout; + } + if (extent.e_len) { + dbg_print_extent("replacing", &extent); + retval = ext2fs_extent_replace(handle, 0, &extent); + if (retval) + goto errout; + retval = ext2fs_extent_fix_parents(handle); + } else { + struct ext2fs_extent newex; + blk64_t old_lblk, next_lblk; + dbg_printf("deleting current extent%s\n", ""); + + /* + * Save the location of the next leaf, then slip + * back to the current extent. + */ + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, + &newex); + if (retval) + goto errout; + old_lblk = newex.e_lblk; + + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_NEXT_LEAF, + &newex); + if (retval == EXT2_ET_EXTENT_NO_NEXT) + next_lblk = old_lblk; + else if (retval) + goto errout; + else + next_lblk = newex.e_lblk; + + retval = ext2fs_extent_goto(handle, old_lblk); + if (retval) + goto errout; + + /* Now delete the extent. */ + retval = ext2fs_extent_delete(handle, 0); + if (retval) + goto errout; + + retval = ext2fs_extent_fix_parents(handle); + if (retval && retval != EXT2_ET_NO_CURRENT_NODE) + goto errout; + retval = 0; + + /* + * Jump forward to the next extent. If there are + * errors, the ext2fs_extent_get down below will + * capture them for us. + */ + (void)ext2fs_extent_goto(handle, next_lblk); + op = EXT2_EXTENT_CURRENT; + } + if (retval) + goto errout; + dbg_printf("Free start %llu, free count = %u\n", + free_start, free_count); + retval = punch_extent_blocks(fs, ino, inode, lfree_start, + free_start, free_count, &freed); + if (retval) + goto errout; + next_extent: + retval = ext2fs_extent_get(handle, op, + &extent); + if (retval == EXT2_ET_EXTENT_NO_NEXT || + retval == EXT2_ET_NO_CURRENT_NODE) + break; + if (retval) + goto errout; + } + dbg_printf("Freed %d blocks\n", freed); + retval = ext2fs_iblk_sub_blocks(fs, inode, freed); +errout: + ext2fs_extent_free(handle); + return retval; +} + +static errcode_t ext2fs_punch_inline_data(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + blk64_t start, + blk64_t end EXT2FS_ATTR((unused))) +{ + errcode_t retval; + + /* + * In libext2fs ext2fs_punch is based on block unit. So that + * means that if start > 0 we don't need to do nothing. Due + * to this we will remove all inline data in ext2fs_punch() + * now. + */ + if (start > 0) + return 0; + + memset((char *)inode->i_block, 0, EXT4_MIN_INLINE_DATA_SIZE); + inode->i_size = 0; + retval = ext2fs_write_inode(fs, ino, inode); + if (retval) + return retval; + + return ext2fs_inline_data_ea_remove(fs, ino); +} + +/* + * Deallocate all logical _blocks_ starting at start to end, inclusive. + * If end is ~0ULL, then this is effectively truncate. + */ +errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + char *block_buf, blk64_t start, + blk64_t end) +{ + errcode_t retval; + struct ext2_inode inode_buf; + + if (start > end) + return EINVAL; + + /* Read inode structure if necessary */ + if (!inode) { + retval = ext2fs_read_inode(fs, ino, &inode_buf); + if (retval) + return retval; + inode = &inode_buf; + } + if (inode->i_flags & EXT4_INLINE_DATA_FL) + return ext2fs_punch_inline_data(fs, ino, inode, start, end); + else if (inode->i_flags & EXT4_EXTENTS_FL) + retval = ext2fs_punch_extent(fs, ino, inode, start, end); + else + retval = ext2fs_punch_ind(fs, inode, block_buf, start, end); + if (retval) + return retval; + +#ifdef PUNCH_DEBUG + printf("%u: write inode size now %u blocks %u\n", + ino, inode->i_size, inode->i_blocks); +#endif + return ext2fs_write_inode(fs, ino, inode); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/rbtree.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/rbtree.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,451 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + (C) 2002 David Woodhouse + + 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 + + linux/lib/rbtree.c +*/ + +#include "rbtree.h" + +static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *right = node->rb_right; + struct rb_node *parent = ext2fs_rb_parent(node); + + if ((node->rb_right = right->rb_left)) + ext2fs_rb_set_parent(right->rb_left, node); + right->rb_left = node; + + ext2fs_rb_set_parent(right, parent); + + if (parent) + { + if (node == parent->rb_left) + parent->rb_left = right; + else + parent->rb_right = right; + } + else + root->rb_node = right; + ext2fs_rb_set_parent(node, right); +} + +static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *left = node->rb_left; + struct rb_node *parent = ext2fs_rb_parent(node); + + if ((node->rb_left = left->rb_right)) + ext2fs_rb_set_parent(left->rb_right, node); + left->rb_right = node; + + ext2fs_rb_set_parent(left, parent); + + if (parent) + { + if (node == parent->rb_right) + parent->rb_right = left; + else + parent->rb_left = left; + } + else + root->rb_node = left; + ext2fs_rb_set_parent(node, left); +} + +void ext2fs_rb_insert_color(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *parent, *gparent; + + while ((parent = ext2fs_rb_parent(node)) && ext2fs_rb_is_red(parent)) + { + gparent = ext2fs_rb_parent(parent); + + if (parent == gparent->rb_left) + { + { + register struct rb_node *uncle = gparent->rb_right; + if (uncle && ext2fs_rb_is_red(uncle)) + { + ext2fs_rb_set_black(uncle); + ext2fs_rb_set_black(parent); + ext2fs_rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_right == node) + { + register struct rb_node *tmp; + __rb_rotate_left(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + ext2fs_rb_set_black(parent); + ext2fs_rb_set_red(gparent); + __rb_rotate_right(gparent, root); + } else { + { + register struct rb_node *uncle = gparent->rb_left; + if (uncle && ext2fs_rb_is_red(uncle)) + { + ext2fs_rb_set_black(uncle); + ext2fs_rb_set_black(parent); + ext2fs_rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_left == node) + { + register struct rb_node *tmp; + __rb_rotate_right(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + ext2fs_rb_set_black(parent); + ext2fs_rb_set_red(gparent); + __rb_rotate_left(gparent, root); + } + } + + ext2fs_rb_set_black(root->rb_node); +} + +static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, + struct rb_root *root) +{ + struct rb_node *other; + + while ((!node || ext2fs_rb_is_black(node)) && node != root->rb_node) + { + if (parent->rb_left == node) + { + other = parent->rb_right; + if (ext2fs_rb_is_red(other)) + { + ext2fs_rb_set_black(other); + ext2fs_rb_set_red(parent); + __rb_rotate_left(parent, root); + other = parent->rb_right; + } + if ((!other->rb_left || ext2fs_rb_is_black(other->rb_left)) && + (!other->rb_right || ext2fs_rb_is_black(other->rb_right))) + { + ext2fs_rb_set_red(other); + node = parent; + parent = ext2fs_rb_parent(node); + } + else + { + if (!other->rb_right || ext2fs_rb_is_black(other->rb_right)) + { + ext2fs_rb_set_black(other->rb_left); + ext2fs_rb_set_red(other); + __rb_rotate_right(other, root); + other = parent->rb_right; + } + ext2fs_rb_set_color(other, ext2fs_rb_color(parent)); + ext2fs_rb_set_black(parent); + ext2fs_rb_set_black(other->rb_right); + __rb_rotate_left(parent, root); + node = root->rb_node; + break; + } + } + else + { + other = parent->rb_left; + if (ext2fs_rb_is_red(other)) + { + ext2fs_rb_set_black(other); + ext2fs_rb_set_red(parent); + __rb_rotate_right(parent, root); + other = parent->rb_left; + } + if ((!other->rb_left || ext2fs_rb_is_black(other->rb_left)) && + (!other->rb_right || ext2fs_rb_is_black(other->rb_right))) + { + ext2fs_rb_set_red(other); + node = parent; + parent = ext2fs_rb_parent(node); + } + else + { + if (!other->rb_left || ext2fs_rb_is_black(other->rb_left)) + { + ext2fs_rb_set_black(other->rb_right); + ext2fs_rb_set_red(other); + __rb_rotate_left(other, root); + other = parent->rb_left; + } + ext2fs_rb_set_color(other, ext2fs_rb_color(parent)); + ext2fs_rb_set_black(parent); + ext2fs_rb_set_black(other->rb_left); + __rb_rotate_right(parent, root); + node = root->rb_node; + break; + } + } + } + if (node) + ext2fs_rb_set_black(node); +} + +void ext2fs_rb_erase(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *child, *parent; + int color; + + if (!node->rb_left) + child = node->rb_right; + else if (!node->rb_right) + child = node->rb_left; + else + { + struct rb_node *old = node, *left; + + node = node->rb_right; + while ((left = node->rb_left) != NULL) + node = left; + + if (ext2fs_rb_parent(old)) { + if (ext2fs_rb_parent(old)->rb_left == old) + ext2fs_rb_parent(old)->rb_left = node; + else + ext2fs_rb_parent(old)->rb_right = node; + } else + root->rb_node = node; + + child = node->rb_right; + parent = ext2fs_rb_parent(node); + color = ext2fs_rb_color(node); + + if (parent == old) { + parent = node; + } else { + if (child) + ext2fs_rb_set_parent(child, parent); + parent->rb_left = child; + + node->rb_right = old->rb_right; + ext2fs_rb_set_parent(old->rb_right, node); + } + + node->rb_parent_color = old->rb_parent_color; + node->rb_left = old->rb_left; + ext2fs_rb_set_parent(old->rb_left, node); + + goto color; + } + + parent = ext2fs_rb_parent(node); + color = ext2fs_rb_color(node); + + if (child) + ext2fs_rb_set_parent(child, parent); + if (parent) + { + if (parent->rb_left == node) + parent->rb_left = child; + else + parent->rb_right = child; + } + else + root->rb_node = child; + + color: + if (color == RB_BLACK) + __rb_erase_color(child, parent, root); +} + +static void ext2fs_rb_augment_path(struct rb_node *node, rb_augment_f func, void *data) +{ + struct rb_node *parent; + +up: + func(node, data); + parent = ext2fs_rb_parent(node); + if (!parent) + return; + + if (node == parent->rb_left && parent->rb_right) + func(parent->rb_right, data); + else if (parent->rb_left) + func(parent->rb_left, data); + + node = parent; + goto up; +} + +/* + * after inserting @node into the tree, update the tree to account for + * both the new entry and any damage done by rebalance + */ +void ext2fs_rb_augment_insert(struct rb_node *node, rb_augment_f func, void *data) +{ + if (node->rb_left) + node = node->rb_left; + else if (node->rb_right) + node = node->rb_right; + + ext2fs_rb_augment_path(node, func, data); +} + +/* + * before removing the node, find the deepest node on the rebalance path + * that will still be there after @node gets removed + */ +struct rb_node *ext2fs_rb_augment_erase_begin(struct rb_node *node) +{ + struct rb_node *deepest; + + if (!node->rb_right && !node->rb_left) + deepest = ext2fs_rb_parent(node); + else if (!node->rb_right) + deepest = node->rb_left; + else if (!node->rb_left) + deepest = node->rb_right; + else { + deepest = ext2fs_rb_next(node); + if (deepest->rb_right) + deepest = deepest->rb_right; + else if (ext2fs_rb_parent(deepest) != node) + deepest = ext2fs_rb_parent(deepest); + } + + return deepest; +} + +/* + * after removal, update the tree to account for the removed entry + * and any rebalance damage. + */ +void ext2fs_rb_augment_erase_end(struct rb_node *node, rb_augment_f func, void *data) +{ + if (node) + ext2fs_rb_augment_path(node, func, data); +} + +/* + * This function returns the first node (in sort order) of the tree. + */ +struct rb_node *ext2fs_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 *ext2fs_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 *ext2fs_rb_next(struct rb_node *node) +{ + struct rb_node *parent; + + if (ext2fs_rb_parent(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 = ext2fs_rb_parent(node)) && node == parent->rb_right) + node = parent; + + return parent; +} + +struct rb_node *ext2fs_rb_prev(struct rb_node *node) +{ + struct rb_node *parent; + + if (ext2fs_rb_parent(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 = ext2fs_rb_parent(node)) && node == parent->rb_left) + node = parent; + + return parent; +} + +void ext2fs_rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root) +{ + struct rb_node *parent = ext2fs_rb_parent(victim); + + /* Set the surrounding nodes to point to the replacement */ + if (parent) { + if (victim == parent->rb_left) + parent->rb_left = new; + else + parent->rb_right = new; + } else { + root->rb_node = new; + } + if (victim->rb_left) + ext2fs_rb_set_parent(victim->rb_left, new); + if (victim->rb_right) + ext2fs_rb_set_parent(victim->rb_right, new); + + /* Copy the pointers/colour from the victim to the replacement */ + *new = *victim; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/rbtree.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/rbtree.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,192 @@ +/* + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 dramatically performances. + I know it's not the cleaner way, but in C (not in C++) to get + performances and genericity... + + Some example of insert and search follows here. The search is a plain + normal search over an ordered tree. The insert instead must be implemented + in two steps: First, the code must insert the element in order as a red leaf + in the tree, and then the support library function rb_insert_color() must + be called. Such function will do the not trivial work to rebalance the + rbtree, if necessary. + +----------------------------------------------------------------------- +static inline struct page * rb_search_page_cache(struct inode * inode, + unsigned long offset) +{ + struct rb_node * n = inode->i_rb_page_cache.rb_node; + struct page * page; + + while (n) + { + page = rb_entry(n, struct page, rb_page_cache); + + if (offset < page->offset) + n = n->rb_left; + else if (offset > page->offset) + n = n->rb_right; + else + return page; + } + return NULL; +} + +static inline struct page * __rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct rb_node ** p = &inode->i_rb_page_cache.rb_node; + struct rb_node * parent = NULL; + struct page * page; + + while (*p) + { + parent = *p; + page = rb_entry(parent, struct page, rb_page_cache); + + if (offset < page->offset) + p = &(*p)->rb_left; + else if (offset > page->offset) + p = &(*p)->rb_right; + else + return page; + } + + rb_link_node(node, parent, p); + + return NULL; +} + +static inline struct page * rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct page * ret; + if ((ret = __rb_insert_page_cache(inode, offset, node))) + goto out; + rb_insert_color(node, &inode->i_rb_page_cache); + out: + return ret; +} +----------------------------------------------------------------------- +*/ + +#ifndef _LINUX_RBTREE_H +#define _LINUX_RBTREE_H + +#include +#include + +#undef offsetof +#ifdef __compiler_offsetof +#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) +#else +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#define container_of(ptr, type, member) ({ \ + const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +struct rb_node +{ + uintptr_t rb_parent_color; +#define RB_RED 0 +#define RB_BLACK 1 + 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 ext2fs_rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) +#define ext2fs_rb_color(r) ((r)->rb_parent_color & 1) +#define ext2fs_rb_is_red(r) (!ext2fs_rb_color(r)) +#define ext2fs_rb_is_black(r) ext2fs_rb_color(r) +#define ext2fs_rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) +#define ext2fs_rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) + +static inline void ext2fs_rb_set_parent(struct rb_node *rb, struct rb_node *p) +{ + rb->rb_parent_color = (rb->rb_parent_color & 3) | (uintptr_t)p; +} +static inline void ext2fs_rb_set_color(struct rb_node *rb, int color) +{ + rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; +} + +#define RB_ROOT (struct rb_root) { NULL, } +#define ext2fs_rb_entry(ptr, type, member) container_of(ptr, type, member) + +static inline int ext2fs_rb_empty_root(struct rb_root *root) +{ + return root->rb_node == NULL; +} + +static inline int ext2fs_rb_empty_node(struct rb_node *node) +{ + return ext2fs_rb_parent(node) == node; +} + +static inline void ext2fs_rb_clear_node(struct rb_node *node) +{ + ext2fs_rb_set_parent(node, node); +} + +extern void ext2fs_rb_insert_color(struct rb_node *, struct rb_root *); +extern void ext2fs_rb_erase(struct rb_node *, struct rb_root *); + +typedef void (*rb_augment_f)(struct rb_node *node, void *data); + +extern void ext2fs_rb_augment_insert(struct rb_node *node, + rb_augment_f func, void *data); +extern struct rb_node *ext2fs_rb_augment_erase_begin(struct rb_node *node); +extern void ext2fs_rb_augment_erase_end(struct rb_node *node, + rb_augment_f func, void *data); + +/* Find logical next and previous nodes in a tree */ +extern struct rb_node *ext2fs_rb_next(struct rb_node *); +extern struct rb_node *ext2fs_rb_prev(struct rb_node *); +extern struct rb_node *ext2fs_rb_first(const struct rb_root *); +extern struct rb_node *ext2fs_rb_last(const struct rb_root *); + +/* Fast replacement of a single node without remove/rebalance/add/rebalance */ +extern void ext2fs_rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root); + +static inline void ext2fs_rb_link_node(struct rb_node * node, + struct rb_node * parent, + struct rb_node ** rb_link) +{ + node->rb_parent_color = (uintptr_t)parent; + node->rb_left = node->rb_right = NULL; + + *rb_link = node; +} + +#endif /* _LINUX_RBTREE_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/read_bb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/read_bb.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,102 @@ +/* + * read_bb --- read the bad blocks inode + * + * Copyright (C) 1994 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +struct read_bb_record { + ext2_badblocks_list bb_list; + errcode_t err; +}; + +/* + * Helper function for ext2fs_read_bb_inode() + */ +#ifdef __TURBOC__ + #pragma argsused +#endif +static int mark_bad_block(ext2_filsys fs, blk_t *block_nr, + e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), + blk_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct read_bb_record *rb = (struct read_bb_record *) priv_data; + + if (blockcnt < 0) + return 0; + + if ((*block_nr < fs->super->s_first_data_block) || + (*block_nr >= ext2fs_blocks_count(fs->super))) + return 0; /* Ignore illegal blocks */ + + rb->err = ext2fs_badblocks_list_add(rb->bb_list, *block_nr); + if (rb->err) + return BLOCK_ABORT; + return 0; +} + +/* + * Reads the current bad blocks from the bad blocks inode. + */ +errcode_t ext2fs_read_bb_inode(ext2_filsys fs, ext2_badblocks_list *bb_list) +{ + errcode_t retval; + struct read_bb_record rb; + struct ext2_inode inode; + blk_t numblocks; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!*bb_list) { + retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode); + if (retval) + return retval; + numblocks = inode.i_blocks; + if (!(ext2fs_has_feature_huge_file(fs->super) && + (inode.i_flags & EXT4_HUGE_FILE_FL))) + numblocks = numblocks / (fs->blocksize / 512); + numblocks += 20; + if (numblocks < 50) + numblocks = 50; + if (numblocks > 50000) + numblocks = 500; + retval = ext2fs_badblocks_list_create(bb_list, numblocks); + if (retval) + return retval; + } + + rb.bb_list = *bb_list; + rb.err = 0; + retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, BLOCK_FLAG_READ_ONLY, + 0, mark_bad_block, &rb); + if (retval) + return retval; + + return rb.err; +} + + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/read_bb_file.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/read_bb_file.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,109 @@ +/* + * read_bb_file.c --- read a list of bad blocks from a FILE * + * + * Copyright (C) 1994, 1995, 2000 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +/* + * Reads a list of bad blocks from a FILE * + */ +errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f, + ext2_badblocks_list *bb_list, + void *priv_data, + void (*invalid)(ext2_filsys fs, + blk_t blk, + char *badstr, + void *priv_data)) +{ + errcode_t retval; + blk64_t blockno; + int count; + char buf[128]; + + if (fs) + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!*bb_list) { + retval = ext2fs_badblocks_list_create(bb_list, 10); + if (retval) + return retval; + } + + while (!feof (f)) { + if (fgets(buf, sizeof(buf), f) == NULL) + break; + count = sscanf(buf, "%llu", &blockno); + if (count <= 0) + continue; + /* Badblocks isn't going to be updated for 64bit */ + if (blockno >> 32) + return EOVERFLOW; + if (fs && + ((blockno < fs->super->s_first_data_block) || + (blockno >= ext2fs_blocks_count(fs->super)))) { + if (invalid) + (invalid)(fs, blockno, buf, priv_data); + continue; + } + retval = ext2fs_badblocks_list_add(*bb_list, blockno); + if (retval) + return retval; + } + return 0; +} + +struct compat_struct { + void (*invalid)(ext2_filsys, blk_t); +}; + +static void call_compat_invalid(ext2_filsys fs, blk_t blk, + char *badstr EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct compat_struct *st; + + st = (struct compat_struct *) priv_data; + if (st->invalid) + (st->invalid)(fs, blk); +} + + +/* + * Reads a list of bad blocks from a FILE * + */ +errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, + ext2_badblocks_list *bb_list, + void (*invalid)(ext2_filsys fs, blk_t blk)) +{ + struct compat_struct st; + + st.invalid = invalid; + + return ext2fs_read_bb_FILE2(fs, f, bb_list, &st, + call_compat_invalid); +} + + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/res_gdt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/res_gdt.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,239 @@ +/* + * res_gdt.c --- reserve blocks for growing the group descriptor table + * during online resizing. + * + * Copyright (C) 2002 Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include +#include "ext2_fs.h" +#include "ext2fs.h" + +/* + * Iterate through the groups which hold BACKUP superblock/GDT copies in an + * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before + * calling this for the first time. In a sparse filesystem it will be the + * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ... + * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ... + */ +static unsigned int list_backups(ext2_filsys fs, unsigned int *three, + unsigned int *five, unsigned int *seven) +{ + unsigned int *min = three; + int mult = 3; + unsigned int ret; + + if (ext2fs_has_feature_sparse_super2(fs->super)) { + if (*min == 1) { + *min += 1; + if (fs->super->s_backup_bgs[0]) + return fs->super->s_backup_bgs[0]; + } + if (*min == 2) { + *min += 1; + if (fs->super->s_backup_bgs[1]) + return fs->super->s_backup_bgs[1]; + } + return fs->group_desc_count; + } + if (!ext2fs_has_feature_sparse_super(fs->super)) { + ret = *min; + *min += 1; + return ret; + } + + if (*five < *min) { + min = five; + mult = 5; + } + if (*seven < *min) { + min = seven; + mult = 7; + } + + ret = *min; + *min *= mult; + + return ret; +} + +/* + * This code assumes that the reserved blocks have already been marked in-use + * during ext2fs_initialize(), so that they are not allocated for other + * uses before we can add them to the resize inode (which has to come + * after the creation of the inode table). + */ +errcode_t ext2fs_create_resize_inode(ext2_filsys fs) +{ + errcode_t retval, retval2; + struct ext2_super_block *sb; + struct ext2_inode inode; + __u32 *dindir_buf, *gdt_buf; + unsigned long long apb, inode_size; + /* FIXME-64 - can't deal with extents */ + blk_t dindir_blk, rsv_off, gdt_off, gdt_blk; + int dindir_dirty = 0, inode_dirty = 0, sb_blk = 0; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + sb = fs->super; + + retval = ext2fs_get_array(2, fs->blocksize, &dindir_buf); + if (retval) + return retval; + gdt_buf = (__u32 *)((char *)dindir_buf + fs->blocksize); + + retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode); + if (retval) + goto out_free; + + /* + * File systems with a blocksize of 1024 and bigalloc have + * sb->s_first_data_block of 0; yet the superblock is still at + * block #1. We compensate for it here. + */ + sb_blk = sb->s_first_data_block; + if (fs->blocksize == 1024 && sb_blk == 0) + sb_blk = 1; + + /* Maximum possible file size (we only use double indirect blocks) */ + apb = EXT2_ADDR_PER_BLOCK(sb); + if ((dindir_blk = inode.i_block[EXT2_DIND_BLOCK])) { +#ifdef RES_GDT_DEBUG + printf("reading GDT dindir %u\n", dindir_blk); +#endif + retval = ext2fs_read_ind_block(fs, dindir_blk, dindir_buf); + if (retval) + goto out_inode; + } else { + blk_t goal = sb_blk + fs->desc_blocks + + sb->s_reserved_gdt_blocks + 2 + + fs->inode_blocks_per_group; + + retval = ext2fs_alloc_block(fs, goal, 0, &dindir_blk); + if (retval) + goto out_free; + inode.i_mode = LINUX_S_IFREG | 0600; + inode.i_links_count = 1; + inode.i_block[EXT2_DIND_BLOCK] = dindir_blk; + ext2fs_iblk_set(fs, &inode, 1); + memset(dindir_buf, 0, fs->blocksize); +#ifdef RES_GDT_DEBUG + printf("allocated GDT dindir %u\n", dindir_blk); +#endif + dindir_dirty = inode_dirty = 1; + inode_size = apb*apb + apb + EXT2_NDIR_BLOCKS; + inode_size *= fs->blocksize; + retval = ext2fs_inode_size_set(fs, &inode, inode_size); + if (retval) + goto out_free; + inode.i_ctime = fs->now ? fs->now : time(0); + } + + for (rsv_off = 0, gdt_off = fs->desc_blocks, + gdt_blk = sb_blk + 1 + fs->desc_blocks; + rsv_off < sb->s_reserved_gdt_blocks; + rsv_off++, gdt_off++, gdt_blk++) { + unsigned int three = 1, five = 5, seven = 7; + unsigned int grp, last = 0; + int gdt_dirty = 0; + + gdt_off %= apb; + if (!dindir_buf[gdt_off]) { + /* FIXME XXX XXX + blk_t new_blk; + + retval = ext2fs_new_block(fs, gdt_blk, 0, &new_blk); + if (retval) + goto out_free; + if (new_blk != gdt_blk) { + // XXX free block + retval = -1; // XXX + } + */ + gdt_dirty = dindir_dirty = inode_dirty = 1; + memset(gdt_buf, 0, fs->blocksize); + dindir_buf[gdt_off] = gdt_blk; + ext2fs_iblk_add_blocks(fs, &inode, 1); +#ifdef RES_GDT_DEBUG + printf("added primary GDT block %u at %u[%u]\n", + gdt_blk, dindir_blk, gdt_off); +#endif + } else if (dindir_buf[gdt_off] == gdt_blk) { +#ifdef RES_GDT_DEBUG + printf("reading primary GDT block %u\n", gdt_blk); +#endif + retval = ext2fs_read_ind_block(fs, gdt_blk, gdt_buf); + if (retval) + goto out_dindir; + } else { +#ifdef RES_GDT_DEBUG + printf("bad primary GDT %u != %u at %u[%u]\n", + dindir_buf[gdt_off], gdt_blk,dindir_blk,gdt_off); +#endif + retval = EXT2_ET_RESIZE_INODE_CORRUPT; + goto out_dindir; + } + + while ((grp = list_backups(fs, &three, &five, &seven)) < + fs->group_desc_count) { + blk_t expect = gdt_blk + grp * sb->s_blocks_per_group; + + if (!gdt_buf[last]) { +#ifdef RES_GDT_DEBUG + printf("added backup GDT %u grp %u@%u[%u]\n", + expect, grp, gdt_blk, last); +#endif + gdt_buf[last] = expect; + ext2fs_iblk_add_blocks(fs, &inode, 1); + gdt_dirty = inode_dirty = 1; + } else if (gdt_buf[last] != expect) { +#ifdef RES_GDT_DEBUG + printf("bad backup GDT %u != %u at %u[%u]\n", + gdt_buf[last], expect, gdt_blk, last); +#endif + retval = EXT2_ET_RESIZE_INODE_CORRUPT; + goto out_dindir; + } + last++; + } + if (gdt_dirty) { +#ifdef RES_GDT_DEBUG + printf("writing primary GDT block %u\n", gdt_blk); +#endif + retval = ext2fs_write_ind_block(fs, gdt_blk, gdt_buf); + if (retval) + goto out_dindir; + } + } + +out_dindir: + if (dindir_dirty) { + retval2 = ext2fs_write_ind_block(fs, dindir_blk, dindir_buf); + if (!retval) + retval = retval2; + } +out_inode: +#ifdef RES_GDT_DEBUG + printf("inode.i_blocks = %u, i_size = %u\n", inode.i_blocks, + inode.i_size); +#endif + if (inode_dirty) { + inode.i_atime = inode.i_mtime = fs->now ? fs->now : time(0); + retval2 = ext2fs_write_new_inode(fs, EXT2_RESIZE_INO, &inode); + if (!retval) + retval = retval2; + } +out_free: + ext2fs_free_mem(&dindir_buf); + return retval; +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/rw_bitmaps.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/rw_bitmaps.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,430 @@ +/* + * rw_bitmaps.c --- routines to read and write the inode and block bitmaps. + * + * Copyright (C) 1993, 1994, 1994, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "e2image.h" + +static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block) +{ + dgrp_t i; + unsigned int j; + int block_nbytes, inode_nbytes; + unsigned int nbits; + errcode_t retval; + char *block_buf = NULL, *inode_buf = NULL; + int csum_flag; + blk64_t blk; + blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block); + ext2_ino_t ino_itr = 1; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!(fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + csum_flag = ext2fs_has_group_desc_csum(fs); + + inode_nbytes = block_nbytes = 0; + if (do_block) { + block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; + retval = io_channel_alloc_buf(fs->io, 0, &block_buf); + if (retval) + goto errout; + memset(block_buf, 0xff, fs->blocksize); + } + if (do_inode) { + inode_nbytes = (size_t) + ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8); + retval = io_channel_alloc_buf(fs->io, 0, &inode_buf); + if (retval) + goto errout; + memset(inode_buf, 0xff, fs->blocksize); + } + + for (i = 0; i < fs->group_desc_count; i++) { + if (!do_block) + goto skip_block_bitmap; + + if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) + ) + goto skip_this_block_bitmap; + + retval = ext2fs_get_block_bitmap_range2(fs->block_map, + blk_itr, block_nbytes << 3, block_buf); + if (retval) + goto errout; + + if (i == fs->group_desc_count - 1) { + /* Force bitmap padding for the last group */ + nbits = EXT2FS_NUM_B2C(fs, + ((ext2fs_blocks_count(fs->super) + - (__u64) fs->super->s_first_data_block) + % (__u64) EXT2_BLOCKS_PER_GROUP(fs->super))); + if (nbits) + for (j = nbits; j < fs->blocksize * 8; j++) + ext2fs_set_bit(j, block_buf); + } + + retval = ext2fs_block_bitmap_csum_set(fs, i, block_buf, + block_nbytes); + if (retval) + return retval; + ext2fs_group_desc_csum_set(fs, i); + fs->flags |= EXT2_FLAG_DIRTY; + + blk = ext2fs_block_bitmap_loc(fs, i); + if (blk) { + retval = io_channel_write_blk64(fs->io, blk, 1, + block_buf); + if (retval) { + retval = EXT2_ET_BLOCK_BITMAP_WRITE; + goto errout; + } + } + skip_this_block_bitmap: + blk_itr += block_nbytes << 3; + skip_block_bitmap: + + if (!do_inode) + continue; + + if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) + ) + goto skip_this_inode_bitmap; + + retval = ext2fs_get_inode_bitmap_range2(fs->inode_map, + ino_itr, inode_nbytes << 3, inode_buf); + if (retval) + goto errout; + + retval = ext2fs_inode_bitmap_csum_set(fs, i, inode_buf, + inode_nbytes); + if (retval) + goto errout; + ext2fs_group_desc_csum_set(fs, i); + fs->flags |= EXT2_FLAG_DIRTY; + + blk = ext2fs_inode_bitmap_loc(fs, i); + if (blk) { + retval = io_channel_write_blk64(fs->io, blk, 1, + inode_buf); + if (retval) { + retval = EXT2_ET_INODE_BITMAP_WRITE; + goto errout; + } + } + skip_this_inode_bitmap: + ino_itr += inode_nbytes << 3; + + } + if (do_block) { + fs->flags &= ~EXT2_FLAG_BB_DIRTY; + ext2fs_free_mem(&block_buf); + } + if (do_inode) { + fs->flags &= ~EXT2_FLAG_IB_DIRTY; + ext2fs_free_mem(&inode_buf); + } + return 0; +errout: + if (inode_buf) + ext2fs_free_mem(&inode_buf); + if (block_buf) + ext2fs_free_mem(&block_buf); + return retval; +} + +static errcode_t mark_uninit_bg_group_blocks(ext2_filsys fs) +{ + dgrp_t i; + blk64_t blk; + ext2fs_block_bitmap bmap = fs->block_map; + + for (i = 0; i < fs->group_desc_count; i++) { + if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT)) + continue; + + ext2fs_reserve_super_and_bgd(fs, i, bmap); + + /* + * Mark the blocks used for the inode table + */ + blk = ext2fs_inode_table_loc(fs, i); + if (blk) + ext2fs_mark_block_bitmap_range2(bmap, blk, + fs->inode_blocks_per_group); + + /* + * Mark block used for the block bitmap + */ + blk = ext2fs_block_bitmap_loc(fs, i); + if (blk) + ext2fs_mark_block_bitmap2(bmap, blk); + + /* + * Mark block used for the inode bitmap + */ + blk = ext2fs_inode_bitmap_loc(fs, i); + if (blk) + ext2fs_mark_block_bitmap2(bmap, blk); + } + return 0; +} + +static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) +{ + dgrp_t i; + char *block_bitmap = 0, *inode_bitmap = 0; + char *buf; + errcode_t retval; + int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; + int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8; + int csum_flag; + unsigned int cnt; + blk64_t blk; + blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block); + blk64_t blk_cnt; + ext2_ino_t ino_itr = 1; + ext2_ino_t ino_cnt; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if ((block_nbytes > (int) fs->blocksize) || + (inode_nbytes > (int) fs->blocksize)) + return EXT2_ET_CORRUPT_SUPERBLOCK; + + fs->write_bitmaps = ext2fs_write_bitmaps; + + csum_flag = ext2fs_has_group_desc_csum(fs); + + retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf); + if (retval) + return retval; + if (do_block) { + if (fs->block_map) + ext2fs_free_block_bitmap(fs->block_map); + strcpy(buf, "block bitmap for "); + strcat(buf, fs->device_name); + retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map); + if (retval) + goto cleanup; + retval = io_channel_alloc_buf(fs->io, 0, &block_bitmap); + if (retval) + goto cleanup; + } else + block_nbytes = 0; + if (do_inode) { + if (fs->inode_map) + ext2fs_free_inode_bitmap(fs->inode_map); + strcpy(buf, "inode bitmap for "); + strcat(buf, fs->device_name); + retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map); + if (retval) + goto cleanup; + retval = io_channel_alloc_buf(fs->io, 0, &inode_bitmap); + if (retval) + goto cleanup; + } else + inode_nbytes = 0; + ext2fs_free_mem(&buf); + + if (fs->flags & EXT2_FLAG_IMAGE_FILE) { + blk = (ext2fs_le32_to_cpu(fs->image_header->offset_inodemap) / fs->blocksize); + ino_cnt = fs->super->s_inodes_count; + while (inode_bitmap && ino_cnt > 0) { + retval = io_channel_read_blk64(fs->image_io, blk++, + 1, inode_bitmap); + if (retval) + goto cleanup; + cnt = fs->blocksize << 3; + if (cnt > ino_cnt) + cnt = ino_cnt; + retval = ext2fs_set_inode_bitmap_range2(fs->inode_map, + ino_itr, cnt, inode_bitmap); + if (retval) + goto cleanup; + ino_itr += cnt; + ino_cnt -= cnt; + } + blk = (ext2fs_le32_to_cpu(fs->image_header->offset_blockmap) / + fs->blocksize); + blk_cnt = EXT2_GROUPS_TO_CLUSTERS(fs->super, + fs->group_desc_count); + while (block_bitmap && blk_cnt > 0) { + retval = io_channel_read_blk64(fs->image_io, blk++, + 1, block_bitmap); + if (retval) + goto cleanup; + cnt = fs->blocksize << 3; + if (cnt > blk_cnt) + cnt = blk_cnt; + retval = ext2fs_set_block_bitmap_range2(fs->block_map, + blk_itr, cnt, block_bitmap); + if (retval) + goto cleanup; + blk_itr += cnt; + blk_cnt -= cnt; + } + goto success_cleanup; + } + + for (i = 0; i < fs->group_desc_count; i++) { + if (block_bitmap) { + blk = ext2fs_block_bitmap_loc(fs, i); + if (csum_flag && + ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) && + ext2fs_group_desc_csum_verify(fs, i)) + blk = 0; + if (blk) { + retval = io_channel_read_blk64(fs->io, blk, + 1, block_bitmap); + if (retval) { + retval = EXT2_ET_BLOCK_BITMAP_READ; + goto cleanup; + } + /* verify block bitmap checksum */ + if (!(fs->flags & + EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_block_bitmap_csum_verify(fs, i, + block_bitmap, block_nbytes)) { + retval = + EXT2_ET_BLOCK_BITMAP_CSUM_INVALID; + goto cleanup; + } + } else + memset(block_bitmap, 0, block_nbytes); + cnt = block_nbytes << 3; + retval = ext2fs_set_block_bitmap_range2(fs->block_map, + blk_itr, cnt, block_bitmap); + if (retval) + goto cleanup; + blk_itr += block_nbytes << 3; + } + if (inode_bitmap) { + blk = ext2fs_inode_bitmap_loc(fs, i); + if (csum_flag && + ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) && + ext2fs_group_desc_csum_verify(fs, i)) + blk = 0; + if (blk) { + retval = io_channel_read_blk64(fs->io, blk, + 1, inode_bitmap); + if (retval) { + retval = EXT2_ET_INODE_BITMAP_READ; + goto cleanup; + } + + /* verify inode bitmap checksum */ + if (!(fs->flags & + EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_inode_bitmap_csum_verify(fs, i, + inode_bitmap, inode_nbytes)) { + retval = + EXT2_ET_INODE_BITMAP_CSUM_INVALID; + goto cleanup; + } + } else + memset(inode_bitmap, 0, inode_nbytes); + cnt = inode_nbytes << 3; + retval = ext2fs_set_inode_bitmap_range2(fs->inode_map, + ino_itr, cnt, inode_bitmap); + if (retval) + goto cleanup; + ino_itr += inode_nbytes << 3; + } + } + + /* Mark group blocks for any BLOCK_UNINIT groups */ + if (do_block) { + retval = mark_uninit_bg_group_blocks(fs); + if (retval) + goto cleanup; + } + +success_cleanup: + if (inode_bitmap) + ext2fs_free_mem(&inode_bitmap); + if (block_bitmap) + ext2fs_free_mem(&block_bitmap); + return 0; + +cleanup: + if (do_block) { + ext2fs_free_mem(&fs->block_map); + fs->block_map = 0; + } + if (do_inode) { + ext2fs_free_mem(&fs->inode_map); + fs->inode_map = 0; + } + if (inode_bitmap) + ext2fs_free_mem(&inode_bitmap); + if (block_bitmap) + ext2fs_free_mem(&block_bitmap); + if (buf) + ext2fs_free_mem(&buf); + return retval; +} + +errcode_t ext2fs_read_inode_bitmap(ext2_filsys fs) +{ + return read_bitmaps(fs, 1, 0); +} + +errcode_t ext2fs_read_block_bitmap(ext2_filsys fs) +{ + return read_bitmaps(fs, 0, 1); +} + +errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs) +{ + return write_bitmaps(fs, 1, 0); +} + +errcode_t ext2fs_write_block_bitmap (ext2_filsys fs) +{ + return write_bitmaps(fs, 0, 1); +} + +errcode_t ext2fs_read_bitmaps(ext2_filsys fs) +{ + if (fs->inode_map && fs->block_map) + return 0; + + return read_bitmaps(fs, !fs->inode_map, !fs->block_map); +} + +errcode_t ext2fs_write_bitmaps(ext2_filsys fs) +{ + int do_inode = fs->inode_map && ext2fs_test_ib_dirty(fs); + int do_block = fs->block_map && ext2fs_test_bb_dirty(fs); + + if (!do_inode && !do_block) + return 0; + + return write_bitmaps(fs, do_inode, do_block); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/sha256.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/sha256.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,254 @@ +/* + * sha256.c --- The sh256 algorithm + * + * Copyright (C) 2004 Sam Hocevar + * (copied from libtomcrypt and then relicensed under GPLv2) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + + +#include "config.h" +#if HAVE_SYS_TYPES_H +#include +#endif +#include "ext2fs.h" + +static const __u32 K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Various logical functions */ +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) RORc((x),(n)) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) +#define RORc(x, y) ( ((((__u32)(x)&0xFFFFFFFFUL)>>(__u32)((y)&31)) | ((__u32)(x)<<(__u32)(32-((y)&31)))) & 0xFFFFFFFFUL) + +#define RND(a,b,c,d,e,f,g,h,i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + +#define STORE64H(x, y) \ + do { \ + (y)[0] = (unsigned char)(((x)>>56)&255);\ + (y)[1] = (unsigned char)(((x)>>48)&255);\ + (y)[2] = (unsigned char)(((x)>>40)&255);\ + (y)[3] = (unsigned char)(((x)>>32)&255);\ + (y)[4] = (unsigned char)(((x)>>24)&255);\ + (y)[5] = (unsigned char)(((x)>>16)&255);\ + (y)[6] = (unsigned char)(((x)>>8)&255);\ + (y)[7] = (unsigned char)((x)&255); } while(0) + +#define STORE32H(x, y) \ + do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ + (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while(0) + +#define LOAD32H(x, y) \ + do { x = ((__u32)((y)[0] & 255)<<24) | \ + ((__u32)((y)[1] & 255)<<16) | \ + ((__u32)((y)[2] & 255)<<8) | \ + ((__u32)((y)[3] & 255)); } while(0) + +struct sha256_state { + __u64 length; + __u32 state[8], curlen; + unsigned char buf[64]; +}; + +/* This is a highly simplified version from libtomcrypt */ +struct hash_state { + struct sha256_state sha256; +}; + +static void sha256_compress(struct hash_state * md, const unsigned char *buf) +{ + __u32 S[8], W[64], t0, t1; + __u32 t; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) { + S[i] = md->sha256.state[i]; + } + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD32H(W[i], buf + (4*i)); + } + + /* fill W[16..63] */ + for (i = 16; i < 64; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + } + + /* Compress */ + for (i = 0; i < 64; ++i) { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i); + t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; + S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; + } + + /* feedback */ + for (i = 0; i < 8; i++) { + md->sha256.state[i] = md->sha256.state[i] + S[i]; + } +} + +static void sha256_init(struct hash_state * md) +{ + md->sha256.curlen = 0; + md->sha256.length = 0; + md->sha256.state[0] = 0x6A09E667UL; + md->sha256.state[1] = 0xBB67AE85UL; + md->sha256.state[2] = 0x3C6EF372UL; + md->sha256.state[3] = 0xA54FF53AUL; + md->sha256.state[4] = 0x510E527FUL; + md->sha256.state[5] = 0x9B05688CUL; + md->sha256.state[6] = 0x1F83D9ABUL; + md->sha256.state[7] = 0x5BE0CD19UL; +} + +#define MIN(x, y) ( ((x)<(y))?(x):(y) ) +#define SHA256_BLOCKSIZE 64 +static void sha256_process(struct hash_state * md, const unsigned char *in, unsigned long inlen) +{ + unsigned long n; + + while (inlen > 0) { + if (md->sha256.curlen == 0 && inlen >= SHA256_BLOCKSIZE) { + sha256_compress(md, in); + md->sha256.length += SHA256_BLOCKSIZE * 8; + in += SHA256_BLOCKSIZE; + inlen -= SHA256_BLOCKSIZE; + } else { + n = MIN(inlen, (SHA256_BLOCKSIZE - md->sha256.curlen)); + memcpy(md->sha256.buf + md->sha256.curlen, in, (size_t)n); + md->sha256.curlen += n; + in += n; + inlen -= n; + if (md->sha256.curlen == SHA256_BLOCKSIZE) { + sha256_compress(md, md->sha256.buf); + md->sha256.length += 8*SHA256_BLOCKSIZE; + md->sha256.curlen = 0; + } + } + } +} + + +static void sha256_done(struct hash_state * md, unsigned char *out) +{ + int i; + + /* increase the length of the message */ + md->sha256.length += md->sha256.curlen * 8; + + /* append the '1' bit */ + md->sha256.buf[md->sha256.curlen++] = (unsigned char)0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->sha256.curlen > 56) { + while (md->sha256.curlen < 64) { + md->sha256.buf[md->sha256.curlen++] = (unsigned char)0; + } + sha256_compress(md, md->sha256.buf); + md->sha256.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->sha256.curlen < 56) { + md->sha256.buf[md->sha256.curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64H(md->sha256.length, md->sha256.buf+56); + sha256_compress(md, md->sha256.buf); + + /* copy output */ + for (i = 0; i < 8; i++) { + STORE32H(md->sha256.state[i], out+(4*i)); + } +} + +void ext2fs_sha256(const unsigned char *in, unsigned long in_size, + unsigned char out[EXT2FS_SHA256_LENGTH]) +{ + struct hash_state md; + + sha256_init(&md); + sha256_process(&md, in, in_size); + sha256_done(&md, out); +} + +#ifdef UNITTEST +static const struct { + char *msg; + unsigned char hash[32]; +} tests[] = { + { "", + { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, + 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, + 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 } + }, + { "abc", + { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad } + }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, + 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, + 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 } + }, +}; + +int main(int argc, char **argv) +{ + int i; + int errors = 0; + unsigned char tmp[32]; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + unsigned char *msg = (unsigned char *) tests[i].msg; + int len = strlen(tests[i].msg); + + ext2fs_sha256(msg, len, tmp); + printf("SHA256 test message %d: ", i); + if (memcmp(tmp, tests[i].hash, 32) != 0) { + printf("FAILED\n"); + errors++; + } else + printf("OK\n"); + } + return errors; +} + +#endif /* UNITTEST */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/sha512.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/sha512.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,302 @@ +/* + * sha512.c --- The sha512 algorithm + * + * Copyright (C) 2004 Sam Hocevar + * (copied from libtomcrypt and then relicensed under GPLv2) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + + +#include "config.h" +#if HAVE_SYS_TYPES_H +#include +#endif +#include "ext2fs.h" + +/* the K array */ +#define CONST64(n) n +static const __u64 K[80] = { + CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd), + CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc), + CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019), + CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118), + CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe), + CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2), + CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1), + CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694), + CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3), + CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65), + CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483), + CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5), + CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210), + CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4), + CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725), + CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70), + CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926), + CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df), + CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8), + CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b), + CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001), + CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30), + CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910), + CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8), + CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53), + CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8), + CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb), + CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3), + CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60), + CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec), + CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9), + CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b), + CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207), + CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178), + CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6), + CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b), + CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493), + CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c), + CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a), + CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817) +}; +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) ROR64c(x, n) +#define R(x, n) (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((__u64)n)) +#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) +#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) +#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) +#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) +#define RND(a,b,c,d,e,f,g,h,i)\ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];\ + t1 = Sigma0(a) + Maj(a, b, c);\ + d += t0;\ + h = t0 + t1; +#define STORE64H(x, y) \ + do { \ + (y)[0] = (unsigned char)(((x)>>56)&255);\ + (y)[1] = (unsigned char)(((x)>>48)&255);\ + (y)[2] = (unsigned char)(((x)>>40)&255);\ + (y)[3] = (unsigned char)(((x)>>32)&255);\ + (y)[4] = (unsigned char)(((x)>>24)&255);\ + (y)[5] = (unsigned char)(((x)>>16)&255);\ + (y)[6] = (unsigned char)(((x)>>8)&255);\ + (y)[7] = (unsigned char)((x)&255); } while(0) + +#define LOAD64H(x, y)\ + do {x = \ + (((__u64)((y)[0] & 255)) << 56) |\ + (((__u64)((y)[1] & 255)) << 48) |\ + (((__u64)((y)[2] & 255)) << 40) |\ + (((__u64)((y)[3] & 255)) << 32) |\ + (((__u64)((y)[4] & 255)) << 24) |\ + (((__u64)((y)[5] & 255)) << 16) |\ + (((__u64)((y)[6] & 255)) << 8) |\ + (((__u64)((y)[7] & 255)));\ + } while(0) + +#define ROR64c(x, y) \ + ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((__u64)(y)&CONST64(63))) | \ + ((x)<<((__u64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF)) + +struct sha512_state { + __u64 length, state[8]; + unsigned long curlen; + unsigned char buf[128]; +}; + +/* This is a highly simplified version from libtomcrypt */ +struct hash_state { + struct sha512_state sha512; +}; + +static void sha512_compress(struct hash_state * md, const unsigned char *buf) +{ + __u64 S[8], W[80], t0, t1; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) { + S[i] = md->sha512.state[i]; + } + + /* copy the state into 1024-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD64H(W[i], buf + (8*i)); + } + + /* fill W[16..79] */ + for (i = 16; i < 80; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + + Gamma0(W[i - 15]) + W[i - 16]; + } + + for (i = 0; i < 80; i += 8) { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); + } + + /* feedback */ + for (i = 0; i < 8; i++) { + md->sha512.state[i] = md->sha512.state[i] + S[i]; + } +} + +static void sha512_init(struct hash_state * md) +{ + md->sha512.curlen = 0; + md->sha512.length = 0; + md->sha512.state[0] = CONST64(0x6a09e667f3bcc908); + md->sha512.state[1] = CONST64(0xbb67ae8584caa73b); + md->sha512.state[2] = CONST64(0x3c6ef372fe94f82b); + md->sha512.state[3] = CONST64(0xa54ff53a5f1d36f1); + md->sha512.state[4] = CONST64(0x510e527fade682d1); + md->sha512.state[5] = CONST64(0x9b05688c2b3e6c1f); + md->sha512.state[6] = CONST64(0x1f83d9abfb41bd6b); + md->sha512.state[7] = CONST64(0x5be0cd19137e2179); +} + +static void sha512_done(struct hash_state * md, unsigned char *out) +{ + int i; + + /* increase the length of the message */ + md->sha512.length += md->sha512.curlen * CONST64(8); + + /* append the '1' bit */ + md->sha512.buf[md->sha512.curlen++] = (unsigned char)0x80; + + /* if the length is currently above 112 bytes we append zeros then + * compress. Then we can fall back to padding zeros and length encoding + * like normal. */ + if (md->sha512.curlen > 112) { + while (md->sha512.curlen < 128) { + md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; + } + sha512_compress(md, md->sha512.buf); + md->sha512.curlen = 0; + } + + /* pad upto 120 bytes of zeroes note: that from 112 to 120 is the 64 MSB + * of the length. We assume that you won't hash > 2^64 bits of data. */ + while (md->sha512.curlen < 120) { + md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64H(md->sha512.length, md->sha512.buf + 120); + sha512_compress(md, md->sha512.buf); + + /* copy output */ + for (i = 0; i < 8; i++) { + STORE64H(md->sha512.state[i], out+(8 * i)); + } +} + +#define MIN(x, y) ( ((x)<(y))?(x):(y) ) +#define SHA512_BLOCKSIZE 128 +static void sha512_process(struct hash_state * md, + const unsigned char *in, + unsigned long inlen) +{ + unsigned long n; + + while (inlen > 0) { + if (md->sha512.curlen == 0 && inlen >= SHA512_BLOCKSIZE) { + sha512_compress(md, in); + md->sha512.length += SHA512_BLOCKSIZE * 8; + in += SHA512_BLOCKSIZE; + inlen -= SHA512_BLOCKSIZE; + } else { + n = MIN(inlen, (SHA512_BLOCKSIZE - md->sha512.curlen)); + memcpy(md->sha512.buf + md->sha512.curlen, + in, (size_t)n); + md->sha512.curlen += n; + in += n; + inlen -= n; + if (md->sha512.curlen == SHA512_BLOCKSIZE) { + sha512_compress(md, md->sha512.buf); + md->sha512.length += SHA512_BLOCKSIZE * 8; + md->sha512.curlen = 0; + } + } + } +} + +void ext2fs_sha512(const unsigned char *in, unsigned long in_size, + unsigned char out[EXT2FS_SHA512_LENGTH]) +{ + struct hash_state md; + + sha512_init(&md); + sha512_process(&md, in, in_size); + sha512_done(&md, out); +} + +#ifdef UNITTEST +static const struct { + char *msg; + unsigned char hash[64]; +} tests[] = { + { "", + { 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, + 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, + 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, + 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, + 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, + 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, + 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, + 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e } + }, + { "abc", + { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, + 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, + 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, + 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, + 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, + 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, + 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, + 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f } + }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + { 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, + 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f, + 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, + 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, + 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, + 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a, + 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, + 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09 } + }, +}; + +int main(int argc, char **argv) +{ + int i; + int errors = 0; + unsigned char tmp[64]; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + unsigned char *msg = (unsigned char *) tests[i].msg; + int len = strlen(tests[i].msg); + + ext2fs_sha512(msg, len, tmp); + printf("SHA512 test message %d: ", i); + if (memcmp(tmp, tests[i].hash, 64) != 0) { + printf("FAILED\n"); + errors++; + } else + printf("OK\n"); + } + return errors; +} + +#endif /* UNITTEST */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/symlink.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/symlink.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,204 @@ +/* + * symlink.c --- make a symlink in the filesystem, based on mkdir.c + * + * Copyright (c) 2012, Intel Corporation. + * All Rights Reserved. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +#ifndef HAVE_STRNLEN +/* + * Incredibly, libc5 doesn't appear to have strnlen. So we have to + * provide our own. + */ +static int my_strnlen(const char * s, int count) +{ + const char *cp = s; + + while (count-- && *cp) + cp++; + return cp - s; +} +#define strnlen(str, x) my_strnlen((str),(x)) +#endif + +errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, + const char *name, const char *target) +{ + errcode_t retval; + struct ext2_inode inode; + ext2_ino_t scratch_ino; + blk64_t blk; + int fastlink, inlinelink; + unsigned int target_len; + char *block_buf = 0; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + /* + * The Linux kernel doesn't allow for links longer than a block + * (counting the NUL terminator) + */ + target_len = strnlen(target, fs->blocksize + 1); + if (target_len >= fs->blocksize) { + retval = EXT2_ET_INVALID_ARGUMENT; + goto cleanup; + } + + /* + * Allocate a data block for slow links + */ + retval = ext2fs_get_mem(fs->blocksize, &block_buf); + if (retval) + goto cleanup; + memset(block_buf, 0, fs->blocksize); + strncpy(block_buf, target, fs->blocksize); + + memset(&inode, 0, sizeof(struct ext2_inode)); + fastlink = (target_len < sizeof(inode.i_block)); + if (!fastlink) { + retval = ext2fs_new_block2(fs, ext2fs_find_inode_goal(fs, ino, + &inode, + 0), + NULL, &blk); + if (retval) + goto cleanup; + } + + /* + * Allocate an inode, if necessary + */ + if (!ino) { + retval = ext2fs_new_inode(fs, parent, LINUX_S_IFLNK | 0755, + 0, &ino); + if (retval) + goto cleanup; + } + + /* + * Create the inode structure.... + */ + inode.i_mode = LINUX_S_IFLNK | 0777; + inode.i_uid = inode.i_gid = 0; + inode.i_links_count = 1; + ext2fs_inode_size_set(fs, &inode, target_len); + /* The time fields are set by ext2fs_write_new_inode() */ + + inlinelink = !fastlink && ext2fs_has_feature_inline_data(fs->super); + if (fastlink) { + /* Fast symlinks, target stored in inode */ + strcpy((char *)&inode.i_block, target); + } else if (inlinelink) { + /* Try inserting an inline data symlink */ + inode.i_flags |= EXT4_INLINE_DATA_FL; + retval = ext2fs_write_new_inode(fs, ino, &inode); + if (retval) + goto cleanup; + retval = ext2fs_inline_data_set(fs, ino, &inode, block_buf, + target_len); + if (retval) { + inode.i_flags &= ~EXT4_INLINE_DATA_FL; + inlinelink = 0; + goto need_block; + } + retval = ext2fs_read_inode(fs, ino, &inode); + if (retval) + goto cleanup; + } else { +need_block: + /* Slow symlinks, target stored in the first block */ + ext2fs_iblk_set(fs, &inode, 1); + if (ext2fs_has_feature_extents(fs->super)) { + /* + * The extent bmap is setup after the inode and block + * have been written out below. + */ + inode.i_flags |= EXT4_EXTENTS_FL; + } + } + + /* + * Write out the inode and inode data block. The inode generation + * number is assigned by write_new_inode, which means that the + * operations using ino must come after it. + */ + if (inlinelink) + retval = ext2fs_write_inode(fs, ino, &inode); + else + retval = ext2fs_write_new_inode(fs, ino, &inode); + if (retval) + goto cleanup; + + if (!fastlink && !inlinelink) { + retval = ext2fs_bmap2(fs, ino, &inode, NULL, BMAP_SET, 0, NULL, + &blk); + if (retval) + goto cleanup; + + retval = io_channel_write_blk64(fs->io, blk, 1, block_buf); + if (retval) + goto cleanup; + } + + /* + * Link the symlink into the filesystem hierarchy + */ + if (name) { + retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, + &scratch_ino); + if (!retval) { + retval = EXT2_ET_FILE_EXISTS; + goto cleanup; + } + if (retval != EXT2_ET_FILE_NOT_FOUND) + goto cleanup; + retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_SYMLINK); + if (retval) + goto cleanup; + } + + /* + * Update accounting.... + */ + if (!fastlink && !inlinelink) + ext2fs_block_alloc_stats2(fs, blk, +1); + ext2fs_inode_alloc_stats2(fs, ino, +1, 0); + +cleanup: + if (block_buf) + ext2fs_free_mem(&block_buf); + return retval; +} + +/* + * Test whether an inode is a fast symlink. + * + * A fast symlink has its symlink data stored in inode->i_block. + */ +int ext2fs_is_fast_symlink(struct ext2_inode *inode) +{ + return LINUX_S_ISLNK(inode->i_mode) && EXT2_I_SIZE(inode) && + EXT2_I_SIZE(inode) < sizeof(inode->i_block); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/unix_io.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/unix_io.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,1244 @@ +/* + * unix_io.c --- This is the Unix (well, really POSIX) implementation + * of the I/O manager. + * + * Implements a one-block write-through cache. + * + * Includes support for Windows NT support under Cygwin. + * + * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + * 2002 by Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) +#define _XOPEN_SOURCE 600 +#define _DARWIN_C_SOURCE +#define _FILE_OFFSET_BITS 64 +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#endif + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#include +#ifdef __linux__ +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_MOUNT_H +#include +#endif +#ifdef HAVE_SYS_PRCTL_H +#include +#else +#define PR_GET_DUMPABLE 3 +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_RESOURCE_H +#include +#endif +#if HAVE_LINUX_FALLOC_H +#include +#endif + +#if defined(__linux__) && defined(_IO) && !defined(BLKROGET) +#define BLKROGET _IO(0x12, 94) /* Get read-only status (0 = read_write). */ +#endif + +#undef ALIGN_DEBUG + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +/* + * For checking structure magic numbers... + */ + +#define EXT2_CHECK_MAGIC(struct, code) \ + if ((struct)->magic != (code)) return (code) + +struct unix_cache { + char *buf; + unsigned long long block; + int access_time; + unsigned dirty:1; + unsigned in_use:1; +}; + +#define CACHE_SIZE 8 +#define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */ +#define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */ + +struct unix_private_data { + int magic; + int dev; + int flags; + int align; + int access_time; + ext2_loff_t offset; + struct unix_cache cache[CACHE_SIZE]; + void *bounce; + struct struct_io_stats io_stats; +}; + +#define IS_ALIGNED(n, align) ((((uintptr_t) n) & \ + ((uintptr_t) ((align)-1))) == 0) + +static errcode_t unix_get_stats(io_channel channel, io_stats *stats) +{ + errcode_t retval = 0; + + struct unix_private_data *data; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct unix_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + + if (stats) + *stats = &data->io_stats; + + return retval; +} + +static char *safe_getenv(const char *arg) +{ + if ((getuid() != geteuid()) || (getgid() != getegid())) + return NULL; +#ifdef HAVE_PRCTL + if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) + return NULL; +#else +#if (defined(linux) && defined(SYS_prctl)) + if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) + return NULL; +#endif +#endif + +#if defined(HAVE_SECURE_GETENV) + return secure_getenv(arg); +#elif defined(HAVE___SECURE_GETENV) + return __secure_getenv(arg); +#else + return getenv(arg); +#endif +} + +/* + * Here are the raw I/O functions + */ +static errcode_t raw_read_blk(io_channel channel, + struct unix_private_data *data, + unsigned long long block, + int count, void *bufv) +{ + errcode_t retval; + ssize_t size; + ext2_loff_t location; + int actual = 0; + unsigned char *buf = bufv; + ssize_t really_read = 0; + + size = (count < 0) ? -count : count * channel->block_size; + data->io_stats.bytes_read += size; + location = ((ext2_loff_t) block * channel->block_size) + data->offset; + + if (data->flags & IO_FLAG_FORCE_BOUNCE) { + if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { + retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; + goto error_out; + } + goto bounce_read; + } + +#ifdef HAVE_PREAD64 + /* Try an aligned pread */ + if ((channel->align == 0) || + (IS_ALIGNED(buf, channel->align) && + IS_ALIGNED(size, channel->align))) { + actual = pread64(data->dev, buf, size, location); + if (actual == size) + return 0; + actual = 0; + } +#elif HAVE_PREAD + /* Try an aligned pread */ + if ((sizeof(off_t) >= sizeof(ext2_loff_t)) && + ((channel->align == 0) || + (IS_ALIGNED(buf, channel->align) && + IS_ALIGNED(size, channel->align)))) { + actual = pread(data->dev, buf, size, location); + if (actual == size) + return 0; + actual = 0; + } +#endif /* HAVE_PREAD */ + + if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { + retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; + goto error_out; + } + if ((channel->align == 0) || + (IS_ALIGNED(buf, channel->align) && + IS_ALIGNED(size, channel->align))) { + actual = read(data->dev, buf, size); + if (actual != size) { + short_read: + if (actual < 0) { + retval = errno; + actual = 0; + } else + retval = EXT2_ET_SHORT_READ; + goto error_out; + } + return 0; + } + +#ifdef ALIGN_DEBUG + printf("raw_read_blk: O_DIRECT fallback: %p %lu\n", buf, + (unsigned long) size); +#endif + + /* + * The buffer or size which we're trying to read isn't aligned + * to the O_DIRECT rules, so we need to do this the hard way... + */ +bounce_read: + while (size > 0) { + actual = read(data->dev, data->bounce, channel->block_size); + if (actual != channel->block_size) { + actual = really_read; + buf -= really_read; + size += really_read; + goto short_read; + } + actual = size; + if (size > channel->block_size) + actual = channel->block_size; + memcpy(buf, data->bounce, actual); + really_read += actual; + size -= actual; + buf += actual; + } + return 0; + +error_out: + if (actual >= 0 && actual < size) + memset((char *) buf+actual, 0, size-actual); + if (channel->read_error) + retval = (channel->read_error)(channel, block, count, buf, + size, actual, retval); + return retval; +} + +static errcode_t raw_write_blk(io_channel channel, + struct unix_private_data *data, + unsigned long long block, + int count, const void *bufv) +{ + ssize_t size; + ext2_loff_t location; + int actual = 0; + errcode_t retval; + const unsigned char *buf = bufv; + + if (count == 1) + size = channel->block_size; + else { + if (count < 0) + size = -count; + else + size = count * channel->block_size; + } + data->io_stats.bytes_written += size; + + location = ((ext2_loff_t) block * channel->block_size) + data->offset; + + if (data->flags & IO_FLAG_FORCE_BOUNCE) { + if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { + retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; + goto error_out; + } + goto bounce_write; + } + +#ifdef HAVE_PWRITE64 + /* Try an aligned pwrite */ + if ((channel->align == 0) || + (IS_ALIGNED(buf, channel->align) && + IS_ALIGNED(size, channel->align))) { + actual = pwrite64(data->dev, buf, size, location); + if (actual == size) + return 0; + } +#elif HAVE_PWRITE + /* Try an aligned pwrite */ + if ((sizeof(off_t) >= sizeof(ext2_loff_t)) && + ((channel->align == 0) || + (IS_ALIGNED(buf, channel->align) && + IS_ALIGNED(size, channel->align)))) { + actual = pwrite(data->dev, buf, size, location); + if (actual == size) + return 0; + } +#endif /* HAVE_PWRITE */ + + if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { + retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; + goto error_out; + } + + if ((channel->align == 0) || + (IS_ALIGNED(buf, channel->align) && + IS_ALIGNED(size, channel->align))) { + actual = write(data->dev, buf, size); + if (actual < 0) { + retval = errno; + goto error_out; + } + if (actual != size) { + short_write: + retval = EXT2_ET_SHORT_WRITE; + goto error_out; + } + return 0; + } + +#ifdef ALIGN_DEBUG + printf("raw_write_blk: O_DIRECT fallback: %p %lu\n", buf, + (unsigned long) size); +#endif + /* + * The buffer or size which we're trying to write isn't aligned + * to the O_DIRECT rules, so we need to do this the hard way... + */ +bounce_write: + while (size > 0) { + if (size < channel->block_size) { + actual = read(data->dev, data->bounce, + channel->block_size); + if (actual != channel->block_size) { + if (actual < 0) { + retval = errno; + goto error_out; + } + memset((char *) data->bounce + actual, 0, + channel->block_size - actual); + } + } + actual = size; + if (size > channel->block_size) + actual = channel->block_size; + memcpy(data->bounce, buf, actual); + if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { + retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; + goto error_out; + } + actual = write(data->dev, data->bounce, channel->block_size); + if (actual < 0) { + retval = errno; + goto error_out; + } + if (actual != channel->block_size) + goto short_write; + size -= actual; + buf += actual; + location += actual; + } + return 0; + +error_out: + if (channel->write_error) + retval = (channel->write_error)(channel, block, count, buf, + size, actual, retval); + return retval; +} + + +/* + * Here we implement the cache functions + */ + +/* Allocate the cache buffers */ +static errcode_t alloc_cache(io_channel channel, + struct unix_private_data *data) +{ + errcode_t retval; + struct unix_cache *cache; + int i; + + data->access_time = 0; + for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { + cache->block = 0; + cache->access_time = 0; + cache->dirty = 0; + cache->in_use = 0; + if (cache->buf) + ext2fs_free_mem(&cache->buf); + retval = io_channel_alloc_buf(channel, 0, &cache->buf); + if (retval) + return retval; + } + if (channel->align || data->flags & IO_FLAG_FORCE_BOUNCE) { + if (data->bounce) + ext2fs_free_mem(&data->bounce); + retval = io_channel_alloc_buf(channel, 0, &data->bounce); + } + return retval; +} + +/* Free the cache buffers */ +static void free_cache(struct unix_private_data *data) +{ + struct unix_cache *cache; + int i; + + data->access_time = 0; + for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { + cache->block = 0; + cache->access_time = 0; + cache->dirty = 0; + cache->in_use = 0; + if (cache->buf) + ext2fs_free_mem(&cache->buf); + } + if (data->bounce) + ext2fs_free_mem(&data->bounce); +} + +#ifndef NO_IO_CACHE +/* + * Try to find a block in the cache. If the block is not found, and + * eldest is a non-zero pointer, then fill in eldest with the cache + * entry to that should be reused. + */ +static struct unix_cache *find_cached_block(struct unix_private_data *data, + unsigned long long block, + struct unix_cache **eldest) +{ + struct unix_cache *cache, *unused_cache, *oldest_cache; + int i; + + unused_cache = oldest_cache = 0; + for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { + if (!cache->in_use) { + if (!unused_cache) + unused_cache = cache; + continue; + } + if (cache->block == block) { + cache->access_time = ++data->access_time; + return cache; + } + if (!oldest_cache || + (cache->access_time < oldest_cache->access_time)) + oldest_cache = cache; + } + if (eldest) + *eldest = (unused_cache) ? unused_cache : oldest_cache; + return 0; +} + +/* + * Reuse a particular cache entry for another block. + */ +static void reuse_cache(io_channel channel, struct unix_private_data *data, + struct unix_cache *cache, unsigned long long block) +{ + if (cache->dirty && cache->in_use) + raw_write_blk(channel, data, cache->block, 1, cache->buf); + + cache->in_use = 1; + cache->dirty = 0; + cache->block = block; + cache->access_time = ++data->access_time; +} + +/* + * Flush all of the blocks in the cache + */ +static errcode_t flush_cached_blocks(io_channel channel, + struct unix_private_data *data, + int invalidate) + +{ + struct unix_cache *cache; + errcode_t retval, retval2; + int i; + + retval2 = 0; + for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { + if (!cache->in_use) + continue; + + if (invalidate) + cache->in_use = 0; + + if (!cache->dirty) + continue; + + retval = raw_write_blk(channel, data, + cache->block, 1, cache->buf); + if (retval) + retval2 = retval; + else + cache->dirty = 0; + } + return retval2; +} +#endif /* NO_IO_CACHE */ + +#ifdef __linux__ +#ifndef BLKDISCARDZEROES +#define BLKDISCARDZEROES _IO(0x12,124) +#endif +#endif + +int ext2fs_open_file(const char *pathname, int flags, mode_t mode) +{ + if (mode) +#if defined(HAVE_OPEN64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) + return open64(pathname, flags, mode); + else + return open64(pathname, flags); +#else + return open(pathname, flags, mode); + else + return open(pathname, flags); +#endif +} + +int ext2fs_stat(const char *path, ext2fs_struct_stat *buf) +{ +#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) + return stat64(path, buf); +#else + return stat(path, buf); +#endif +} + +int ext2fs_fstat(int fd, ext2fs_struct_stat *buf) +{ +#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) + return fstat64(fd, buf); +#else + return fstat(fd, buf); +#endif +} + + +static errcode_t unix_open_channel(const char *name, int fd, + int flags, io_channel *channel, + io_manager io_mgr) +{ + io_channel io = NULL; + struct unix_private_data *data = NULL; + errcode_t retval; + ext2fs_struct_stat st; +#ifdef __linux__ + struct utsname ut; +#endif + + if (safe_getenv("UNIX_IO_FORCE_BOUNCE")) + flags |= IO_FLAG_FORCE_BOUNCE; + +#ifdef __linux__ + /* + * We need to make sure any previous errors in the block + * device are thrown away, sigh. + */ + (void) fsync(fd); +#endif + + retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io); + if (retval) + goto cleanup; + memset(io, 0, sizeof(struct struct_io_channel)); + io->magic = EXT2_ET_MAGIC_IO_CHANNEL; + retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data); + if (retval) + goto cleanup; + + io->manager = io_mgr; + retval = ext2fs_get_mem(strlen(name)+1, &io->name); + if (retval) + goto cleanup; + + strcpy(io->name, name); + io->private_data = data; + io->block_size = 1024; + io->read_error = 0; + io->write_error = 0; + io->refcount = 1; + + memset(data, 0, sizeof(struct unix_private_data)); + data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; + data->io_stats.num_fields = 2; + data->flags = flags; + data->dev = fd; + +#if defined(O_DIRECT) + if (flags & IO_FLAG_DIRECT_IO) + io->align = ext2fs_get_dio_alignment(data->dev); +#elif defined(F_NOCACHE) + if (flags & IO_FLAG_DIRECT_IO) + io->align = 4096; +#endif + + /* + * If the device is really a block device, then set the + * appropriate flag, otherwise we can set DISCARD_ZEROES flag + * because we are going to use punch hole instead of discard + * and if it succeed, subsequent read from sparse area returns + * zero. + */ + if (ext2fs_fstat(data->dev, &st) == 0) { + if (ext2fsP_is_disk_device(st.st_mode)) + io->flags |= CHANNEL_FLAGS_BLOCK_DEVICE; + else + io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES; + } + +#ifdef BLKDISCARDZEROES + { + int zeroes = 0; + if (ioctl(data->dev, BLKDISCARDZEROES, &zeroes) == 0 && + zeroes) + io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES; + } +#endif + +#if defined(__CYGWIN__) + /* + * Some operating systems require that the buffers be aligned, + * regardless of O_DIRECT + */ + if (!io->align) + io->align = 512; +#endif + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + if (io->flags & CHANNEL_FLAGS_BLOCK_DEVICE) { + int dio_align = ext2fs_get_dio_alignment(fd); + + if (io->align < dio_align) + io->align = dio_align; + } +#endif + + if ((retval = alloc_cache(io, data))) + goto cleanup; + +#ifdef BLKROGET + if (flags & IO_FLAG_RW) { + int error; + int readonly = 0; + + /* Is the block device actually writable? */ + error = ioctl(data->dev, BLKROGET, &readonly); + if (!error && readonly) { + retval = EPERM; + goto cleanup; + } + } +#endif + +#ifdef __linux__ +#undef RLIM_INFINITY +#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4))) +#define RLIM_INFINITY ((unsigned long)(~0UL>>1)) +#else +#define RLIM_INFINITY (~0UL) +#endif + /* + * Work around a bug in 2.4.10-2.4.18 kernels where writes to + * block devices are wrongly getting hit by the filesize + * limit. This workaround isn't perfect, since it won't work + * if glibc wasn't built against 2.2 header files. (Sigh.) + * + */ + if ((flags & IO_FLAG_RW) && + (uname(&ut) == 0) && + ((ut.release[0] == '2') && (ut.release[1] == '.') && + (ut.release[2] == '4') && (ut.release[3] == '.') && + (ut.release[4] == '1') && (ut.release[5] >= '0') && + (ut.release[5] < '8')) && + (ext2fs_fstat(data->dev, &st) == 0) && + (ext2fsP_is_disk_device(st.st_mode))) { + struct rlimit rlim; + + rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY; + setrlimit(RLIMIT_FSIZE, &rlim); + getrlimit(RLIMIT_FSIZE, &rlim); + if (((unsigned long) rlim.rlim_cur) < + ((unsigned long) rlim.rlim_max)) { + rlim.rlim_cur = rlim.rlim_max; + setrlimit(RLIMIT_FSIZE, &rlim); + } + } +#endif + *channel = io; + return 0; + +cleanup: + if (data) { + if (data->dev >= 0) + close(data->dev); + free_cache(data); + ext2fs_free_mem(&data); + } + if (io) { + if (io->name) { + ext2fs_free_mem(&io->name); + } + ext2fs_free_mem(&io); + } + return retval; +} + +static errcode_t unixfd_open(const char *str_fd, int flags, + io_channel *channel) +{ + int fd; + int fd_flags; + + fd = atoi(str_fd); +#if defined(HAVE_FCNTL) + fd_flags = fcntl(fd, F_GETFD); + if (fd_flags == -1) + return -EBADF; + + flags = 0; + if (fd_flags & O_RDWR) + flags |= IO_FLAG_RW; + if (fd_flags & O_EXCL) + flags |= IO_FLAG_EXCLUSIVE; +#if defined(O_DIRECT) + if (fd_flags & O_DIRECT) + flags |= IO_FLAG_DIRECT_IO; +#endif +#endif /* HAVE_FCNTL */ + + return unix_open_channel(str_fd, fd, flags, channel, unixfd_io_manager); +} + +static errcode_t unix_open(const char *name, int flags, + io_channel *channel) +{ + int fd = -1; + int open_flags; + + if (name == 0) + return EXT2_ET_BAD_DEVICE_NAME; + + open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY; + if (flags & IO_FLAG_EXCLUSIVE) + open_flags |= O_EXCL; +#if defined(O_DIRECT) + if (flags & IO_FLAG_DIRECT_IO) + open_flags |= O_DIRECT; +#endif + fd = ext2fs_open_file(name, open_flags, 0); + if (fd < 0) + return errno; +#if defined(F_NOCACHE) && !defined(IO_DIRECT) + if (flags & IO_FLAG_DIRECT_IO) { + if (fcntl(fd, F_NOCACHE, 1) < 0) + return errno; + } +#endif + return unix_open_channel(name, fd, flags, channel, unix_io_manager); +} + +static errcode_t unix_close(io_channel channel) +{ + struct unix_private_data *data; + errcode_t retval = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct unix_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + + if (--channel->refcount > 0) + return 0; + +#ifndef NO_IO_CACHE + retval = flush_cached_blocks(channel, data, 0); +#endif + + if (close(data->dev) < 0) + retval = errno; + free_cache(data); + + ext2fs_free_mem(&channel->private_data); + if (channel->name) + ext2fs_free_mem(&channel->name); + ext2fs_free_mem(&channel); + return retval; +} + +static errcode_t unix_set_blksize(io_channel channel, int blksize) +{ + struct unix_private_data *data; + errcode_t retval; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct unix_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + + if (channel->block_size != blksize) { +#ifndef NO_IO_CACHE + if ((retval = flush_cached_blocks(channel, data, 0))) + return retval; +#endif + + channel->block_size = blksize; + free_cache(data); + if ((retval = alloc_cache(channel, data))) + return retval; + } + return 0; +} + +static errcode_t unix_read_blk64(io_channel channel, unsigned long long block, + int count, void *buf) +{ + struct unix_private_data *data; + struct unix_cache *cache, *reuse[READ_DIRECT_SIZE]; + errcode_t retval; + char *cp; + int i, j; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct unix_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + +#ifdef NO_IO_CACHE + return raw_read_blk(channel, data, block, count, buf); +#else + /* + * If we're doing an odd-sized read or a very large read, + * flush out the cache and then do a direct read. + */ + if (count < 0 || count > WRITE_DIRECT_SIZE) { + if ((retval = flush_cached_blocks(channel, data, 0))) + return retval; + return raw_read_blk(channel, data, block, count, buf); + } + + cp = buf; + while (count > 0) { + /* If it's in the cache, use it! */ + if ((cache = find_cached_block(data, block, &reuse[0]))) { +#ifdef DEBUG + printf("Using cached block %lu\n", block); +#endif + memcpy(cp, cache->buf, channel->block_size); + count--; + block++; + cp += channel->block_size; + continue; + } + if (count == 1) { + /* + * Special case where we read directly into the + * cache buffer; important in the O_DIRECT case + */ + cache = reuse[0]; + reuse_cache(channel, data, cache, block); + if ((retval = raw_read_blk(channel, data, block, 1, + cache->buf))) { + cache->in_use = 0; + return retval; + } + memcpy(cp, cache->buf, channel->block_size); + return 0; + } + + /* + * Find the number of uncached blocks so we can do a + * single read request + */ + for (i=1; i < count; i++) + if (find_cached_block(data, block+i, &reuse[i])) + break; +#ifdef DEBUG + printf("Reading %d blocks starting at %lu\n", i, block); +#endif + if ((retval = raw_read_blk(channel, data, block, i, cp))) + return retval; + + /* Save the results in the cache */ + for (j=0; j < i; j++) { + count--; + cache = reuse[j]; + reuse_cache(channel, data, cache, block++); + memcpy(cache->buf, cp, channel->block_size); + cp += channel->block_size; + } + } + return 0; +#endif /* NO_IO_CACHE */ +} + +static errcode_t unix_read_blk(io_channel channel, unsigned long block, + int count, void *buf) +{ + return unix_read_blk64(channel, block, count, buf); +} + +static errcode_t unix_write_blk64(io_channel channel, unsigned long long block, + int count, const void *buf) +{ + struct unix_private_data *data; + struct unix_cache *cache, *reuse; + errcode_t retval = 0; + const char *cp; + int writethrough; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct unix_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + +#ifdef NO_IO_CACHE + return raw_write_blk(channel, data, block, count, buf); +#else + /* + * If we're doing an odd-sized write or a very large write, + * flush out the cache completely and then do a direct write. + */ + if (count < 0 || count > WRITE_DIRECT_SIZE) { + if ((retval = flush_cached_blocks(channel, data, 1))) + return retval; + return raw_write_blk(channel, data, block, count, buf); + } + + /* + * For a moderate-sized multi-block write, first force a write + * if we're in write-through cache mode, and then fill the + * cache with the blocks. + */ + writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH; + if (writethrough) + retval = raw_write_blk(channel, data, block, count, buf); + + cp = buf; + while (count > 0) { + cache = find_cached_block(data, block, &reuse); + if (!cache) { + cache = reuse; + reuse_cache(channel, data, cache, block); + } + if (cache->buf != cp) + memcpy(cache->buf, cp, channel->block_size); + cache->dirty = !writethrough; + count--; + block++; + cp += channel->block_size; + } + return retval; +#endif /* NO_IO_CACHE */ +} + +static errcode_t unix_cache_readahead(io_channel channel, + unsigned long long block, + unsigned long long count) +{ +#ifdef POSIX_FADV_WILLNEED + struct unix_private_data *data; + + data = (struct unix_private_data *)channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + return posix_fadvise(data->dev, + (ext2_loff_t)block * channel->block_size + data->offset, + (ext2_loff_t)count * channel->block_size, + POSIX_FADV_WILLNEED); +#else + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +static errcode_t unix_write_blk(io_channel channel, unsigned long block, + int count, const void *buf) +{ + return unix_write_blk64(channel, block, count, buf); +} + +static errcode_t unix_write_byte(io_channel channel, unsigned long offset, + int size, const void *buf) +{ + struct unix_private_data *data; + errcode_t retval = 0; + ssize_t actual; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct unix_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + + if (channel->align != 0) { +#ifdef ALIGN_DEBUG + printf("unix_write_byte: O_DIRECT fallback\n"); +#endif + return EXT2_ET_UNIMPLEMENTED; + } + +#ifndef NO_IO_CACHE + /* + * Flush out the cache completely + */ + if ((retval = flush_cached_blocks(channel, data, 1))) + return retval; +#endif + + if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0) + return errno; + + actual = write(data->dev, buf, size); + if (actual < 0) + return errno; + if (actual != size) + return EXT2_ET_SHORT_WRITE; + + return 0; +} + +/* + * Flush data buffers to disk. + */ +static errcode_t unix_flush(io_channel channel) +{ + struct unix_private_data *data; + errcode_t retval = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct unix_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + +#ifndef NO_IO_CACHE + retval = flush_cached_blocks(channel, data, 0); +#endif +#ifdef HAVE_FSYNC + if (!retval && fsync(data->dev) != 0) + return errno; +#endif + return retval; +} + +static errcode_t unix_set_option(io_channel channel, const char *option, + const char *arg) +{ + struct unix_private_data *data; + unsigned long long tmp; + char *end; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct unix_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + + if (!strcmp(option, "offset")) { + if (!arg) + return EXT2_ET_INVALID_ARGUMENT; + + tmp = strtoull(arg, &end, 0); + if (*end) + return EXT2_ET_INVALID_ARGUMENT; + data->offset = tmp; + if (data->offset < 0) + return EXT2_ET_INVALID_ARGUMENT; + return 0; + } + return EXT2_ET_INVALID_ARGUMENT; +} + +#if defined(__linux__) && !defined(BLKDISCARD) +#define BLKDISCARD _IO(0x12,119) +#endif + +static errcode_t unix_discard(io_channel channel, unsigned long long block, + unsigned long long count) +{ + struct unix_private_data *data; + int ret; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct unix_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + + if (channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE) { +#ifdef BLKDISCARD + __u64 range[2]; + + range[0] = (__u64)(block) * channel->block_size + data->offset; + range[1] = (__u64)(count) * channel->block_size; + + ret = ioctl(data->dev, BLKDISCARD, &range); +#else + goto unimplemented; +#endif + } else { +#if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE) + /* + * If we are not on block device, try to use punch hole + * to reclaim free space. + */ + ret = fallocate(data->dev, + FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + (off_t)(block) * channel->block_size + data->offset, + (off_t)(count) * channel->block_size); +#else + goto unimplemented; +#endif + } + if (ret < 0) { + if (errno == EOPNOTSUPP) + goto unimplemented; + return errno; + } + return 0; +unimplemented: + return EXT2_ET_UNIMPLEMENTED; +} + +/* parameters might not be used if OS doesn't support zeroout */ +#if __GNUC_PREREQ (4, 6) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif +static errcode_t unix_zeroout(io_channel channel, unsigned long long block, + unsigned long long count) +{ + struct unix_private_data *data; + int ret; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct unix_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + + if (safe_getenv("UNIX_IO_NOZEROOUT")) + goto unimplemented; + + if (channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE) { + /* Not implemented until the BLKZEROOUT mess is fixed */ + goto unimplemented; + } else { + /* Regular file, try to use truncate/punch/zero. */ + struct stat statbuf; + + if (count == 0) + return 0; + /* + * If we're trying to zero a range past the end of the file, + * extend the file size, then truncate everything. + */ + ret = fstat(data->dev, &statbuf); + if (ret) + goto err; + if ((unsigned long long) statbuf.st_size < + (block + count) * channel->block_size + data->offset) { + ret = ftruncate(data->dev, + (block + count) * channel->block_size + data->offset); + if (ret) + goto err; + } +#if defined(HAVE_FALLOCATE) && (defined(FALLOC_FL_ZERO_RANGE) || \ + (defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE))) +#if defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE) + ret = fallocate(data->dev, + FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + (off_t)(block) * channel->block_size + data->offset, + (off_t)(count) * channel->block_size); + if (ret == 0) + goto err; +#endif +#ifdef FALLOC_FL_ZERO_RANGE + ret = fallocate(data->dev, + FALLOC_FL_ZERO_RANGE, + (off_t)(block) * channel->block_size + data->offset, + (off_t)(count) * channel->block_size); +#endif +#else + goto unimplemented; +#endif /* HAVE_FALLOCATE && (ZERO_RANGE || (PUNCH_HOLE && KEEP_SIZE)) */ + } +err: + if (ret < 0) { + if (errno == EOPNOTSUPP) + goto unimplemented; + return errno; + } + return 0; +unimplemented: + return EXT2_ET_UNIMPLEMENTED; +} +#if __GNUC_PREREQ (4, 6) +#pragma GCC diagnostic pop +#endif + +static struct struct_io_manager struct_unix_manager = { + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name = "Unix I/O Manager", + .open = unix_open, + .close = unix_close, + .set_blksize = unix_set_blksize, + .read_blk = unix_read_blk, + .write_blk = unix_write_blk, + .flush = unix_flush, + .write_byte = unix_write_byte, + .set_option = unix_set_option, + .get_stats = unix_get_stats, + .read_blk64 = unix_read_blk64, + .write_blk64 = unix_write_blk64, + .discard = unix_discard, + .cache_readahead = unix_cache_readahead, + .zeroout = unix_zeroout, +}; + +io_manager unix_io_manager = &struct_unix_manager; + +static struct struct_io_manager struct_unixfd_manager = { + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name = "Unix fd I/O Manager", + .open = unixfd_open, + .close = unix_close, + .set_blksize = unix_set_blksize, + .read_blk = unix_read_blk, + .write_blk = unix_write_blk, + .flush = unix_flush, + .write_byte = unix_write_byte, + .set_option = unix_set_option, + .get_stats = unix_get_stats, + .read_blk64 = unix_read_blk64, + .write_blk64 = unix_write_blk64, + .discard = unix_discard, + .cache_readahead = unix_cache_readahead, + .zeroout = unix_zeroout, +}; + +io_manager unixfd_io_manager = &struct_unixfd_manager; diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/unlink.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/unlink.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,100 @@ +/* + * unlink.c --- delete links in a ext2fs directory + * + * Copyright (C) 1993, 1994, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +struct link_struct { + const char *name; + int namelen; + ext2_ino_t inode; + int flags; + struct ext2_dir_entry *prev; + int done; +}; + +#ifdef __TURBOC__ + #pragma argsused +#endif +static int unlink_proc(struct ext2_dir_entry *dirent, + int offset, + int blocksize EXT2FS_ATTR((unused)), + char *buf EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct link_struct *ls = (struct link_struct *) priv_data; + struct ext2_dir_entry *prev; + + prev = ls->prev; + ls->prev = dirent; + + if (ls->name) { + if (ext2fs_dirent_name_len(dirent) != ls->namelen) + return 0; + if (strncmp(ls->name, dirent->name, ext2fs_dirent_name_len(dirent))) + return 0; + } + if (ls->inode) { + if (dirent->inode != ls->inode) + return 0; + } else { + if (!dirent->inode) + return 0; + } + + if (offset) + prev->rec_len += dirent->rec_len; + else + dirent->inode = 0; + ls->done++; + return DIRENT_ABORT|DIRENT_CHANGED; +} + +#ifdef __TURBOC__ + #pragma argsused +#endif +errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, + const char *name, ext2_ino_t ino, + int flags EXT2FS_ATTR((unused))) +{ + errcode_t retval; + struct link_struct ls; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!name && !ino) + return EXT2_ET_INVALID_ARGUMENT; + + if (!(fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + ls.name = name; + ls.namelen = name ? strlen(name) : 0; + ls.inode = ino; + ls.flags = 0; + ls.done = 0; + ls.prev = 0; + + retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY, + 0, unlink_proc, &ls); + if (retval) + return retval; + + return (ls.done) ? 0 : EXT2_ET_DIR_NO_SPACE; +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/valid_blk.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/valid_blk.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,68 @@ +/* + * valid_blk.c --- does the inode have valid blocks? + * + * Copyright 1997 by Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "ext2_fs.h" +#include "ext2fs.h" + +/* + * This function returns 1 if the inode's block entries actually + * contain block entries. + */ +int ext2fs_inode_has_valid_blocks2(ext2_filsys fs, struct ext2_inode *inode) +{ + /* + * Only directories, regular files, and some symbolic links + * have valid block entries. + */ + if (!LINUX_S_ISDIR(inode->i_mode) && !LINUX_S_ISREG(inode->i_mode) && + !LINUX_S_ISLNK(inode->i_mode)) + return 0; + + /* + * If the symbolic link is a "fast symlink", then the symlink + * target is stored in the block entries. + */ + if (LINUX_S_ISLNK (inode->i_mode)) { + if (ext2fs_file_acl_block(fs, inode) == 0) { + /* With no EA block, we can rely on i_blocks */ + if (inode->i_blocks == 0) + return 0; + } else { + /* With an EA block, life gets more tricky */ + if (inode->i_size >= EXT2_N_BLOCKS*4) + return 1; /* definitely using i_block[] */ + if (inode->i_size > 4 && inode->i_block[1] == 0) + return 1; /* definitely using i_block[] */ + return 0; /* Probably a fast symlink */ + } + } + + /* + * If this inode has inline data, it shouldn't have valid block + * entries. + */ + if (inode->i_flags & EXT4_INLINE_DATA_FL) + return 0; + return 1; +} + +int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode) +{ + return ext2fs_inode_has_valid_blocks2(NULL, inode); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/version.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/version.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,57 @@ +/* + * version.c --- Return the version of the ext2 library + * + * Copyright (C) 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#include + +#include "ext2_fs.h" +#include "ext2fs.h" + +#include "version.h" + +static const char *lib_version = E2FSPROGS_VERSION; +static const char *lib_date = E2FSPROGS_DATE; + +int ext2fs_parse_version_string(const char *ver_string) +{ + const char *cp; + int version = 0, dot_count = 0; + + for (cp = ver_string; *cp; cp++) { + if (*cp == '.') { + if (dot_count++) + break; + else + continue; + } + if (!isdigit(*cp)) + break; + version = (version * 10) + (*cp - '0'); + } + return version; +} + + +int ext2fs_get_library_version(const char **ver_string, + const char **date_string) +{ + if (ver_string) + *ver_string = lib_version; + if (date_string) + *date_string = lib_date; + + return ext2fs_parse_version_string(lib_version); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libext2fs/write_bb_file.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libext2fs/write_bb_file.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,35 @@ +/* + * write_bb_file.c --- write a list of bad blocks to a FILE * + * + * Copyright (C) 1994, 1995 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include + +#include "ext2_fs.h" +#include "ext2fs.h" + +errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list, + unsigned int flags EXT2FS_ATTR((unused)), + FILE *f) +{ + badblocks_iterate bb_iter; + blk_t blk; + errcode_t retval; + + retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter); + if (retval) + return retval; + + while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) { + fprintf(f, "%u\n", blk); + } + ext2fs_badblocks_list_iterate_end(bb_iter); + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,24 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../../.. + +TARGET = libsupport.a libsupport.so +PC_FILENAME = libsupport +SRC_C = \ + argv_parse.c cstring.c mkquota.c parse_qtype.c plausible.c profile.c \ + profile_helpers.c prof_err.c quotaio.c quotaio_tree.c quotaio_v2.c \ + dict.c + +REQUIRES_LIBS = libblkid + +PRIVATE_INCDIR += \ + $(PKGDIR)/lib $(PKGDIR)/lib/libsupport \ + $(PKGDIR)/include/libsupport \ + $(PKGDIR)/include/libsupport/support \ + $(PKGDIR)/include/libext2fs \ + $(PKGDIR)/include/libet \ + $(PKGDIR)/include/libe2p \ + $(PKGDIR)/include/libblkid + +CONTRIB_INCDIR = libsupport + +include $(L4DIR)/mk/lib.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/argv_parse.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/argv_parse.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,166 @@ +/* + * argv_parse.c --- utility function for parsing a string into a + * argc, argv array. + * + * This file defines a function argv_parse() which parsing a + * passed-in string, handling double quotes and backslashes, and + * creates an allocated argv vector which can be freed using the + * argv_free() function. + * + * See argv_parse.h for the formal definition of the functions. + * + * Copyright 1999 by Theodore Ts'o. + * + * Permission to use, copy, modify, and distribute this software for + * any purpose with or without fee is hereby granted, provided that + * the above copyright notice and this permission notice appear in all + * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE + * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't + * it sick that the U.S. culture of lawsuit-happy lawyers requires + * this kind of disclaimer?) + * + * Version 1.1, modified 2/27/1999 + */ + +#include "config.h" +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include "argv_parse.h" + +#define STATE_WHITESPACE 1 +#define STATE_TOKEN 2 +#define STATE_QUOTED 3 + +/* + * Returns 0 on success, -1 on failure. + */ +int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv) +{ + int argc = 0, max_argc = 0; + char **argv, **new_argv, *buf, ch; + char *cp = 0, *outcp = 0; + int state = STATE_WHITESPACE; + + buf = malloc(strlen(in_buf)+1); + if (!buf) + return -1; + + max_argc = 0; argc = 0; argv = 0; + outcp = buf; + for (cp = in_buf; (ch = *cp); cp++) { + if (state == STATE_WHITESPACE) { + if (isspace((int) ch)) + continue; + /* Not whitespace, so start a new token */ + state = STATE_TOKEN; + if (argc >= max_argc) { + max_argc += 3; + new_argv = realloc(argv, + (max_argc+1)*sizeof(char *)); + if (!new_argv) { + free(argv); + free(buf); + return -1; + } + argv = new_argv; + } + argv[argc++] = outcp; + } + if (state == STATE_QUOTED) { + if (ch == '"') + state = STATE_TOKEN; + else + *outcp++ = ch; + continue; + } + /* Must be processing characters in a word */ + if (isspace((int) ch)) { + /* + * Terminate the current word and start + * looking for the beginning of the next word. + */ + *outcp++ = 0; + state = STATE_WHITESPACE; + continue; + } + if (ch == '"') { + state = STATE_QUOTED; + continue; + } + if (ch == '\\') { + ch = *++cp; + switch (ch) { + case '\0': + ch = '\\'; cp--; break; + case 'n': + ch = '\n'; break; + case 't': + ch = '\t'; break; + case 'b': + ch = '\b'; break; + } + } + *outcp++ = ch; + } + if (state != STATE_WHITESPACE) + *outcp++ = '\0'; + if (argv == 0) { + argv = malloc(sizeof(char *)); + free(buf); + } + argv[argc] = 0; + if (ret_argc) + *ret_argc = argc; + if (ret_argv) + *ret_argv = argv; + return 0; +} + +void argv_free(char **argv) +{ + free(*argv); + free(argv); +} + +#ifdef DEBUG +/* + * For debugging + */ + +#include + +int main(int argc, char **argv) +{ + int ac, ret; + char **av, **cpp; + char buf[256]; + + while (!feof(stdin)) { + if (fgets(buf, sizeof(buf), stdin) == NULL) + break; + ret = argv_parse(buf, &ac, &av); + if (ret != 0) { + printf("Argv_parse returned %d!\n", ret); + continue; + } + printf("Argv_parse returned %d arguments...\n", ac); + for (cpp = av; *cpp; cpp++) { + if (cpp != av) + printf(", "); + printf("'%s'", *cpp); + } + printf("\n"); + argv_free(av); + } + exit(0); +} +#endif /* DEBUG */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/argv_parse.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/argv_parse.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,43 @@ +/* + * argv_parse.h --- header file for the argv parser. + * + * This file defines the interface for the functions argv_parse() and + * argv_free(). + * + *********************************************************************** + * int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv) + * + * This function takes as its first argument a string which it will + * parse into an argv argument vector, with each white-space separated + * word placed into its own slot in the argv. This function handles + * double quotes and backslashes so that the parsed words can contain + * special characters. The count of the number words found in the + * parsed string, as well as the argument vector, are returned into + * ret_argc and ret_argv, respectively. + *********************************************************************** + * extern void argv_free(char **argv); + * + * This function frees the argument vector created by argv_parse(). + *********************************************************************** + * + * Copyright 1999 by Theodore Ts'o. + * + * Permission to use, copy, modify, and distribute this software for + * any purpose with or without fee is hereby granted, provided that + * the above copyright notice and this permission notice appear in all + * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE + * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't + * it sick that the U.S. culture of lawsuit-happy lawyers requires + * this kind of disclaimer?) + * + * Version 1.1, modified 2/27/1999 + */ + +extern int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv); +extern void argv_free(char **argv); diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/common.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,36 @@ +/* + * + * Various things common for all utilities + * + */ + +#ifndef __QUOTA_COMMON_H__ +#define __QUOTA_COMMON_H__ + +#if EXT2_FLAT_INCLUDES +#include "e2_types.h" +#else +#include +#endif /* EXT2_FLAT_INCLUDES */ + +/* #define DEBUG_QUOTA 1 */ + +#ifndef __attribute__ +# if !defined __GNUC__ || __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ +# define __attribute__(x) +# endif +#endif + +#define log_err(format, arg ...) \ + fprintf(stderr, "[ERROR] %s:%d:%s:: " format "\n", \ + __FILE__, __LINE__, __func__, ## arg) + +#ifdef DEBUG_QUOTA +# define log_debug(format, arg ...) \ + fprintf(stderr, "[DEBUG] %s:%d:%s:: " format "\n", \ + __FILE__, __LINE__, __func__, ## arg) +#else +# define log_debug(...) +#endif + +#endif /* __QUOTA_COMMON_H__ */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/cstring.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/cstring.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,162 @@ +/* + * cstring.c -- parse and print strings using the C escape sequences + */ + +#include "config.h" +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif +#include + +#include "cstring.h" + +int parse_c_string(char *str) +{ + char *to, *from, ch; + int v; + + to = from = str; + + for (to = from = (char *) str; + *from && *from != '"'; to++, from++) { + if (*from == '\\') { + ch = *(++from); + switch (ch) { + case 'a': + *to = '\a'; + break; + case 'b': + *to = '\b'; + break; + case 'f': + *to = '\f'; + break; + case 'n': + *to = '\n'; + break; + case 't': + *to = '\t'; + break; + case 'v': + *to = '\v'; + break; + case 'x': + ch = *(from + 1); + if (ch >= 'a' && ch <= 'f') + ch = ch - 'a' + 'A'; + if (ch >= '0' && ch <= '9') + v = ch - '0'; + else if (ch >= 'A' && ch <= 'F') + v = ch + 10 - 'A'; + else { + *to = 'x'; + break; + } + from++; + ch = *(from + 1); + if (ch >= 'a' && ch <= 'f') + ch = ch - 'a' + 'A'; + if (ch >= '0' && ch <= '9') + v = (v * 16) + (ch - '0'); + else if (ch >= 'A' && ch <= 'F') + v = (v * 16) + (ch + 10 - 'A'); + else { + *to = 'x'; + from--; + break; + } + from++; + *to = v; + break; + default: + if (ch >= '0' && ch <= '9') { + v = ch - '0'; + ch = *(from + 1); + if (ch >= '0' && ch <= '9') { + from++; + v = (8 * v) + (ch - '0'); + ch = *(from + 1); + if (ch >= '0' && ch <= '9') { + from++; + v = (8 * v) + (ch - '0'); + } + } + ch = v; + } + *to = ch; + } + continue; + } + *to = *from; + } + *to = '\0'; + return to - (char *) str; +} + +void print_c_string(FILE *f, const char *cp, int len) +{ + unsigned char ch; + + if (len < 0) + len = strlen(cp); + + while (len--) { + ch = *cp++; + if (ch == '\a') + fputs("\\a", f); + else if (ch == '\b') + fputs("\\b", f); + else if (ch == '\f') + fputs("\\f", f); + else if (ch == '\n') + fputs("\\n", f); + else if (ch == '\t') + fputs("\\t", f); + else if (ch == '\v') + fputs("\\v", f); + else if (ch == '\\') + fputs("\\\\", f); + else if (ch == '\'') + fputs("\\\'", f); + else if (ch == '\"') + fputs("\\\"", f); + else if ((ch < 32) || (ch > 126)) + fprintf(f, "\\%03o", ch); + else + fputc(ch, f); + } +} + +#ifdef DEBUG_PROGRAM +int main(int argc, char **argv) +{ + char buf[4096]; + int c, raw = 0; + + while ((c = getopt(argc, argv, "r")) != EOF) { + switch (c) { + case 'r': + raw++; + break; + default: + fprintf(stderr, "Usage: %s [-r]\n", argv[0]); + exit(1); + } + } + + while (!feof(stdin)) { + if (fgets(buf, sizeof(buf), stdin) == NULL) + break; + c = parse_c_string(buf); + if (raw) + fputs(buf, stdout); + else { + print_c_string(stdout, buf, c); + printf(" <%d>\n", c); + } + } +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/cstring.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/cstring.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,6 @@ +/* + * cstring.h -- header file for C string parse/print utilities + */ + +extern int parse_c_string(char *str); +extern void print_c_string(FILE *f, const char *cp, int len); diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/dict.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/dict.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,1531 @@ +/* + * Dictionary Abstract Data Type + * Copyright (C) 1997 Kaz Kylheku + * + * Free Software License: + * + * All rights are reserved by the author, with the following exceptions: + * Permission is granted to freely reproduce and distribute this software, + * possibly in exchange for a fee, provided that this copyright notice appears + * intact. Permission is also granted to adapt this software to produce + * derivative works, as long as the modified versions carry this copyright + * notice and additional notices stating that the work has been modified. + * This source code may be translated into executable form and incorporated + * into proprietary software; there is no requirement for such software to + * contain a copyright notice related to this source. + * + * $Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $ + * $Name: kazlib_1_20 $ + */ + +#define DICT_NODEBUG + +#ifdef __GNUC__ +#define EXT2FS_ATTR(x) __attribute__(x) +#else +#define EXT2FS_ATTR(x) +#endif + +#include "config.h" +#include +#include +#ifdef DICT_NODEBUG +#define dict_assert(x) +#else +#include +#define dict_assert(x) assert(x) +#endif +#define DICT_IMPLEMENTATION +#include "dict.h" + +#ifdef KAZLIB_RCSID +static const char rcsid[] = "$Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $"; +#endif + +/* + * These macros provide short convenient names for structure members, + * which are embellished with dict_ prefixes so that they are + * properly confined to the documented namespace. It's legal for a + * program which uses dict to define, for instance, a macro called ``parent''. + * Such a macro would interfere with the dnode_t struct definition. + * In general, highly portable and reusable C modules which expose their + * structures need to confine structure member names to well-defined spaces. + * The resulting identifiers aren't necessarily convenient to use, nor + * readable, in the implementation, however! + */ + +#define left dict_left +#define right dict_right +#define parent dict_parent +#define color dict_color +#define key dict_key +#define data dict_data + +#define nilnode dict_nilnode +#define nodecount dict_nodecount +#define maxcount dict_maxcount +#define compare dict_compare +#define allocnode dict_allocnode +#define freenode dict_freenode +#define context dict_context +#define dupes dict_dupes + +#define dictptr dict_dictptr + +#define dict_root(D) ((D)->nilnode.left) +#define dict_nil(D) (&(D)->nilnode) +#define DICT_DEPTH_MAX 64 + +static dnode_t *dnode_alloc(void *context); +static void dnode_free(dnode_t *node, void *context); + +/* + * Perform a ``left rotation'' adjustment on the tree. The given node P and + * its right child C are rearranged so that the P instead becomes the left + * child of C. The left subtree of C is inherited as the new right subtree + * for P. The ordering of the keys within the tree is thus preserved. + */ + +static void rotate_left(dnode_t *upper) +{ + dnode_t *lower, *lowleft, *upparent; + + lower = upper->right; + upper->right = lowleft = lower->left; + lowleft->parent = upper; + + lower->parent = upparent = upper->parent; + + /* don't need to check for root node here because root->parent is + the sentinel nil node, and root->parent->left points back to root */ + + if (upper == upparent->left) { + upparent->left = lower; + } else { + dict_assert (upper == upparent->right); + upparent->right = lower; + } + + lower->left = upper; + upper->parent = lower; +} + +/* + * This operation is the ``mirror'' image of rotate_left. It is + * the same procedure, but with left and right interchanged. + */ + +static void rotate_right(dnode_t *upper) +{ + dnode_t *lower, *lowright, *upparent; + + lower = upper->left; + upper->left = lowright = lower->right; + lowright->parent = upper; + + lower->parent = upparent = upper->parent; + + if (upper == upparent->right) { + upparent->right = lower; + } else { + dict_assert (upper == upparent->left); + upparent->left = lower; + } + + lower->right = upper; + upper->parent = lower; +} + +/* + * Do a postorder traversal of the tree rooted at the specified + * node and free everything under it. Used by dict_free(). + */ + +static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil) +{ + if (node == nil) + return; + free_nodes(dict, node->left, nil); + free_nodes(dict, node->right, nil); + dict->freenode(node, dict->context); +} + +/* + * This procedure performs a verification that the given subtree is a binary + * search tree. It performs an inorder traversal of the tree using the + * dict_next() successor function, verifying that the key of each node is + * strictly lower than that of its successor, if duplicates are not allowed, + * or lower or equal if duplicates are allowed. This function is used for + * debugging purposes. + */ +#ifndef DICT_NODEBUG +static int verify_bintree(dict_t *dict) +{ + dnode_t *first, *next; + + first = dict_first(dict); + + if (dict->dupes) { + while (first && (next = dict_next(dict, first))) { + if (dict->compare(first->key, next->key) > 0) + return 0; + first = next; + } + } else { + while (first && (next = dict_next(dict, first))) { + if (dict->compare(first->key, next->key) >= 0) + return 0; + first = next; + } + } + return 1; +} + +/* + * This function recursively verifies that the given binary subtree satisfies + * three of the red black properties. It checks that every red node has only + * black children. It makes sure that each node is either red or black. And it + * checks that every path has the same count of black nodes from root to leaf. + * It returns the blackheight of the given subtree; this allows blackheights to + * be computed recursively and compared for left and right siblings for + * mismatches. It does not check for every nil node being black, because there + * is only one sentinel nil node. The return value of this function is the + * black height of the subtree rooted at the node ``root'', or zero if the + * subtree is not red-black. + */ + +static unsigned int verify_redblack(dnode_t *nil, dnode_t *root) +{ + unsigned height_left, height_right; + + if (root != nil) { + height_left = verify_redblack(nil, root->left); + height_right = verify_redblack(nil, root->right); + if (height_left == 0 || height_right == 0) + return 0; + if (height_left != height_right) + return 0; + if (root->color == dnode_red) { + if (root->left->color != dnode_black) + return 0; + if (root->right->color != dnode_black) + return 0; + return height_left; + } + if (root->color != dnode_black) + return 0; + return height_left + 1; + } + return 1; +} + +/* + * Compute the actual count of nodes by traversing the tree and + * return it. This could be compared against the stored count to + * detect a mismatch. + */ + +static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root) +{ + if (root == nil) + return 0; + else + return 1 + verify_node_count(nil, root->left) + + verify_node_count(nil, root->right); +} +#endif + +/* + * Verify that the tree contains the given node. This is done by + * traversing all of the nodes and comparing their pointers to the + * given pointer. Returns 1 if the node is found, otherwise + * returns zero. It is intended for debugging purposes. + */ + +static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node) +{ + if (root != nil) { + return root == node + || verify_dict_has_node(nil, root->left, node) + || verify_dict_has_node(nil, root->right, node); + } + return 0; +} + + +#ifdef E2FSCK_NOTUSED +/* + * Dynamically allocate and initialize a dictionary object. + */ + +dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp) +{ + dict_t *new = malloc(sizeof *new); + + if (new) { + new->compare = comp; + new->allocnode = dnode_alloc; + new->freenode = dnode_free; + new->context = NULL; + new->nodecount = 0; + new->maxcount = maxcount; + new->nilnode.left = &new->nilnode; + new->nilnode.right = &new->nilnode; + new->nilnode.parent = &new->nilnode; + new->nilnode.color = dnode_black; + new->dupes = 0; + } + return new; +} +#endif /* E2FSCK_NOTUSED */ + +/* + * Select a different set of node allocator routines. + */ + +void dict_set_allocator(dict_t *dict, dnode_alloc_t al, + dnode_free_t fr, void *context) +{ + dict_assert (dict_count(dict) == 0); + dict_assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL)); + + dict->allocnode = al ? al : dnode_alloc; + dict->freenode = fr ? fr : dnode_free; + dict->context = context; +} + +#ifdef E2FSCK_NOTUSED +/* + * Free a dynamically allocated dictionary object. Removing the nodes + * from the tree before deleting it is required. + */ + +void dict_destroy(dict_t *dict) +{ + dict_assert (dict_isempty(dict)); + free(dict); +} +#endif + +/* + * Free all the nodes in the dictionary by using the dictionary's + * installed free routine. The dictionary is emptied. + */ + +void dict_free_nodes(dict_t *dict) +{ + dnode_t *nil = dict_nil(dict), *root = dict_root(dict); + free_nodes(dict, root, nil); + dict->nodecount = 0; + dict->nilnode.left = &dict->nilnode; + dict->nilnode.right = &dict->nilnode; +} + +#ifdef E2FSCK_NOTUSED +/* + * Obsolescent function, equivalent to dict_free_nodes + */ +void dict_free(dict_t *dict) +{ +#ifdef KAZLIB_OBSOLESCENT_DEBUG + dict_assert ("call to obsolescent function dict_free()" && 0); +#endif + dict_free_nodes(dict); +} +#endif + +/* + * Initialize a user-supplied dictionary object. + */ + +dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp) +{ + dict->compare = comp; + dict->allocnode = dnode_alloc; + dict->freenode = dnode_free; + dict->context = NULL; + dict->nodecount = 0; + dict->maxcount = maxcount; + dict->nilnode.left = &dict->nilnode; + dict->nilnode.right = &dict->nilnode; + dict->nilnode.parent = &dict->nilnode; + dict->nilnode.color = dnode_black; + dict->dupes = 0; + return dict; +} + +#ifdef E2FSCK_NOTUSED +/* + * Initialize a dictionary in the likeness of another dictionary + */ + +void dict_init_like(dict_t *dict, const dict_t *template) +{ + dict->compare = template->compare; + dict->allocnode = template->allocnode; + dict->freenode = template->freenode; + dict->context = template->context; + dict->nodecount = 0; + dict->maxcount = template->maxcount; + dict->nilnode.left = &dict->nilnode; + dict->nilnode.right = &dict->nilnode; + dict->nilnode.parent = &dict->nilnode; + dict->nilnode.color = dnode_black; + dict->dupes = template->dupes; + + dict_assert (dict_similar(dict, template)); +} + +/* + * Remove all nodes from the dictionary (without freeing them in any way). + */ + +static void dict_clear(dict_t *dict) +{ + dict->nodecount = 0; + dict->nilnode.left = &dict->nilnode; + dict->nilnode.right = &dict->nilnode; + dict->nilnode.parent = &dict->nilnode; + dict_assert (dict->nilnode.color == dnode_black); +} +#endif /* E2FSCK_NOTUSED */ + + +/* + * Verify the integrity of the dictionary structure. This is provided for + * debugging purposes, and should be placed in assert statements. Just because + * this function succeeds doesn't mean that the tree is not corrupt. Certain + * corruptions in the tree may simply cause undefined behavior. + */ +#ifndef DICT_NODEBUG +int dict_verify(dict_t *dict) +{ + dnode_t *nil = dict_nil(dict), *root = dict_root(dict); + + /* check that the sentinel node and root node are black */ + if (root->color != dnode_black) + return 0; + if (nil->color != dnode_black) + return 0; + if (nil->right != nil) + return 0; + /* nil->left is the root node; check that its parent pointer is nil */ + if (nil->left->parent != nil) + return 0; + /* perform a weak test that the tree is a binary search tree */ + if (!verify_bintree(dict)) + return 0; + /* verify that the tree is a red-black tree */ + if (!verify_redblack(nil, root)) + return 0; + if (verify_node_count(nil, root) != dict_count(dict)) + return 0; + return 1; +} +#endif /* DICT_NODEBUG */ + +#ifdef E2FSCK_NOTUSED +/* + * Determine whether two dictionaries are similar: have the same comparison and + * allocator functions, and same status as to whether duplicates are allowed. + */ +int dict_similar(const dict_t *left, const dict_t *right) +{ + if (left->compare != right->compare) + return 0; + + if (left->allocnode != right->allocnode) + return 0; + + if (left->freenode != right->freenode) + return 0; + + if (left->context != right->context) + return 0; + + if (left->dupes != right->dupes) + return 0; + + return 1; +} +#endif /* E2FSCK_NOTUSED */ + +/* + * Locate a node in the dictionary having the given key. + * If the node is not found, a null a pointer is returned (rather than + * a pointer that dictionary's nil sentinel node), otherwise a pointer to the + * located node is returned. + */ + +dnode_t *dict_lookup(dict_t *dict, const void *key) +{ + dnode_t *root = dict_root(dict); + dnode_t *nil = dict_nil(dict); + dnode_t *saved; + int result; + + /* simple binary search adapted for trees that contain duplicate keys */ + + while (root != nil) { + result = dict->compare(key, root->key); + if (result < 0) + root = root->left; + else if (result > 0) + root = root->right; + else { + if (!dict->dupes) { /* no duplicates, return match */ + return root; + } else { /* could be dupes, find leftmost one */ + do { + saved = root; + root = root->left; + while (root != nil && dict->compare(key, root->key)) + root = root->right; + } while (root != nil); + return saved; + } + } + } + + return NULL; +} + +#ifdef E2FSCK_NOTUSED +/* + * Look for the node corresponding to the lowest key that is equal to or + * greater than the given key. If there is no such node, return null. + */ + +dnode_t *dict_lower_bound(dict_t *dict, const void *key) +{ + dnode_t *root = dict_root(dict); + dnode_t *nil = dict_nil(dict); + dnode_t *tentative = 0; + + while (root != nil) { + int result = dict->compare(key, root->key); + + if (result > 0) { + root = root->right; + } else if (result < 0) { + tentative = root; + root = root->left; + } else { + if (!dict->dupes) { + return root; + } else { + tentative = root; + root = root->left; + } + } + } + + return tentative; +} + +/* + * Look for the node corresponding to the greatest key that is equal to or + * lower than the given key. If there is no such node, return null. + */ + +dnode_t *dict_upper_bound(dict_t *dict, const void *key) +{ + dnode_t *root = dict_root(dict); + dnode_t *nil = dict_nil(dict); + dnode_t *tentative = 0; + + while (root != nil) { + int result = dict->compare(key, root->key); + + if (result < 0) { + root = root->left; + } else if (result > 0) { + tentative = root; + root = root->right; + } else { + if (!dict->dupes) { + return root; + } else { + tentative = root; + root = root->right; + } + } + } + + return tentative; +} +#endif + +/* + * Insert a node into the dictionary. The node should have been + * initialized with a data field. All other fields are ignored. + * The behavior is undefined if the user attempts to insert into + * a dictionary that is already full (for which the dict_isfull() + * function returns true). + */ + +void dict_insert(dict_t *dict, dnode_t *node, const void *key) +{ + dnode_t *where = dict_root(dict), *nil = dict_nil(dict); + dnode_t *parent = nil, *uncle, *grandpa; + int result = -1; + + node->key = key; + + dict_assert (!dict_isfull(dict)); + dict_assert (!dict_contains(dict, node)); + dict_assert (!dnode_is_in_a_dict(node)); + + /* basic binary tree insert */ + + while (where != nil) { + parent = where; + result = dict->compare(key, where->key); + /* trap attempts at duplicate key insertion unless it's explicitly allowed */ + dict_assert (dict->dupes || result != 0); + if (result < 0) + where = where->left; + else + where = where->right; + } + + dict_assert (where == nil); + + if (result < 0) + parent->left = node; + else + parent->right = node; + + node->parent = parent; + node->left = nil; + node->right = nil; + + dict->nodecount++; + + /* red black adjustments */ + + node->color = dnode_red; + + while (parent->color == dnode_red) { + grandpa = parent->parent; + if (parent == grandpa->left) { + uncle = grandpa->right; + if (uncle->color == dnode_red) { /* red parent, red uncle */ + parent->color = dnode_black; + uncle->color = dnode_black; + grandpa->color = dnode_red; + node = grandpa; + parent = grandpa->parent; + } else { /* red parent, black uncle */ + if (node == parent->right) { + rotate_left(parent); + parent = node; + dict_assert (grandpa == parent->parent); + /* rotation between parent and child preserves grandpa */ + } + parent->color = dnode_black; + grandpa->color = dnode_red; + rotate_right(grandpa); + break; + } + } else { /* symmetric cases: parent == parent->parent->right */ + uncle = grandpa->left; + if (uncle->color == dnode_red) { + parent->color = dnode_black; + uncle->color = dnode_black; + grandpa->color = dnode_red; + node = grandpa; + parent = grandpa->parent; + } else { + if (node == parent->left) { + rotate_right(parent); + parent = node; + dict_assert (grandpa == parent->parent); + } + parent->color = dnode_black; + grandpa->color = dnode_red; + rotate_left(grandpa); + break; + } + } + } + + dict_root(dict)->color = dnode_black; + + dict_assert (dict_verify(dict)); +} + +#ifdef E2FSCK_NOTUSED +/* + * Delete the given node from the dictionary. If the given node does not belong + * to the given dictionary, undefined behavior results. A pointer to the + * deleted node is returned. + */ + +dnode_t *dict_delete(dict_t *dict, dnode_t *delete) +{ + dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent; + + /* basic deletion */ + + dict_assert (!dict_isempty(dict)); + dict_assert (dict_contains(dict, delete)); + + /* + * If the node being deleted has two children, then we replace it with its + * successor (i.e. the leftmost node in the right subtree.) By doing this, + * we avoid the traditional algorithm under which the successor's key and + * value *only* move to the deleted node and the successor is spliced out + * from the tree. We cannot use this approach because the user may hold + * pointers to the successor, or nodes may be inextricably tied to some + * other structures by way of embedding, etc. So we must splice out the + * node we are given, not some other node, and must not move contents from + * one node to another behind the user's back. + */ + + if (delete->left != nil && delete->right != nil) { + dnode_t *next = dict_next(dict, delete); + dnode_t *nextparent = next->parent; + dnode_color_t nextcolor = next->color; + + dict_assert (next != nil); + dict_assert (next->parent != nil); + dict_assert (next->left == nil); + + /* + * First, splice out the successor from the tree completely, by + * moving up its right child into its place. + */ + + child = next->right; + child->parent = nextparent; + + if (nextparent->left == next) { + nextparent->left = child; + } else { + dict_assert (nextparent->right == next); + nextparent->right = child; + } + + /* + * Now that the successor has been extricated from the tree, install it + * in place of the node that we want deleted. + */ + + next->parent = delparent; + next->left = delete->left; + next->right = delete->right; + next->left->parent = next; + next->right->parent = next; + next->color = delete->color; + delete->color = nextcolor; + + if (delparent->left == delete) { + delparent->left = next; + } else { + dict_assert (delparent->right == delete); + delparent->right = next; + } + + } else { + dict_assert (delete != nil); + dict_assert (delete->left == nil || delete->right == nil); + + child = (delete->left != nil) ? delete->left : delete->right; + + child->parent = delparent = delete->parent; + + if (delete == delparent->left) { + delparent->left = child; + } else { + dict_assert (delete == delparent->right); + delparent->right = child; + } + } + + delete->parent = NULL; + delete->right = NULL; + delete->left = NULL; + + dict->nodecount--; + + dict_assert (verify_bintree(dict)); + + /* red-black adjustments */ + + if (delete->color == dnode_black) { + dnode_t *parent, *sister; + + dict_root(dict)->color = dnode_red; + + while (child->color == dnode_black) { + parent = child->parent; + if (child == parent->left) { + sister = parent->right; + dict_assert (sister != nil); + if (sister->color == dnode_red) { + sister->color = dnode_black; + parent->color = dnode_red; + rotate_left(parent); + sister = parent->right; + dict_assert (sister != nil); + } + if (sister->left->color == dnode_black + && sister->right->color == dnode_black) { + sister->color = dnode_red; + child = parent; + } else { + if (sister->right->color == dnode_black) { + dict_assert (sister->left->color == dnode_red); + sister->left->color = dnode_black; + sister->color = dnode_red; + rotate_right(sister); + sister = parent->right; + dict_assert (sister != nil); + } + sister->color = parent->color; + sister->right->color = dnode_black; + parent->color = dnode_black; + rotate_left(parent); + break; + } + } else { /* symmetric case: child == child->parent->right */ + dict_assert (child == parent->right); + sister = parent->left; + dict_assert (sister != nil); + if (sister->color == dnode_red) { + sister->color = dnode_black; + parent->color = dnode_red; + rotate_right(parent); + sister = parent->left; + dict_assert (sister != nil); + } + if (sister->right->color == dnode_black + && sister->left->color == dnode_black) { + sister->color = dnode_red; + child = parent; + } else { + if (sister->left->color == dnode_black) { + dict_assert (sister->right->color == dnode_red); + sister->right->color = dnode_black; + sister->color = dnode_red; + rotate_left(sister); + sister = parent->left; + dict_assert (sister != nil); + } + sister->color = parent->color; + sister->left->color = dnode_black; + parent->color = dnode_black; + rotate_right(parent); + break; + } + } + } + + child->color = dnode_black; + dict_root(dict)->color = dnode_black; + } + + dict_assert (dict_verify(dict)); + + return delete; +} +#endif /* E2FSCK_NOTUSED */ + +/* + * Allocate a node using the dictionary's allocator routine, give it + * the data item. + */ + +int dict_alloc_insert(dict_t *dict, const void *key, void *data) +{ + dnode_t *node = dict->allocnode(dict->context); + + if (node) { + dnode_init(node, data); + dict_insert(dict, node, key); + return 1; + } + return 0; +} + +#ifdef E2FSCK_NOTUSED +void dict_delete_free(dict_t *dict, dnode_t *node) +{ + dict_delete(dict, node); + dict->freenode(node, dict->context); +} +#endif + +/* + * Return the node with the lowest (leftmost) key. If the dictionary is empty + * (that is, dict_isempty(dict) returns 1) a null pointer is returned. + */ + +dnode_t *dict_first(dict_t *dict) +{ + dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left; + + if (root != nil) + while ((left = root->left) != nil) + root = left; + + return (root == nil) ? NULL : root; +} + +/* + * Return the node with the highest (rightmost) key. If the dictionary is empty + * (that is, dict_isempty(dict) returns 1) a null pointer is returned. + */ + +dnode_t *dict_last(dict_t *dict) +{ + dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right; + + if (root != nil) + while ((right = root->right) != nil) + root = right; + + return (root == nil) ? NULL : root; +} + +/* + * Return the given node's successor node---the node which has the + * next key in the the left to right ordering. If the node has + * no successor, a null pointer is returned rather than a pointer to + * the nil node. + */ + +dnode_t *dict_next(dict_t *dict, dnode_t *curr) +{ + dnode_t *nil = dict_nil(dict), *parent, *left; + + if (curr->right != nil) { + curr = curr->right; + while ((left = curr->left) != nil) + curr = left; + return curr; + } + + parent = curr->parent; + + while (parent != nil && curr == parent->right) { + curr = parent; + parent = curr->parent; + } + + return (parent == nil) ? NULL : parent; +} + +/* + * Return the given node's predecessor, in the key order. + * The nil sentinel node is returned if there is no predecessor. + */ + +dnode_t *dict_prev(dict_t *dict, dnode_t *curr) +{ + dnode_t *nil = dict_nil(dict), *parent, *right; + + if (curr->left != nil) { + curr = curr->left; + while ((right = curr->right) != nil) + curr = right; + return curr; + } + + parent = curr->parent; + + while (parent != nil && curr == parent->left) { + curr = parent; + parent = curr->parent; + } + + return (parent == nil) ? NULL : parent; +} + +void dict_allow_dupes(dict_t *dict) +{ + dict->dupes = 1; +} + +#undef dict_count +#undef dict_isempty +#undef dict_isfull +#undef dnode_get +#undef dnode_put +#undef dnode_getkey + +dictcount_t dict_count(dict_t *dict) +{ + return dict->nodecount; +} + +int dict_isempty(dict_t *dict) +{ + return dict->nodecount == 0; +} + +int dict_isfull(dict_t *dict) +{ + return dict->nodecount == dict->maxcount; +} + +int dict_contains(dict_t *dict, dnode_t *node) +{ + return verify_dict_has_node(dict_nil(dict), dict_root(dict), node); +} + +static dnode_t *dnode_alloc(void *context EXT2FS_ATTR((unused))) +{ + return malloc(sizeof *dnode_alloc(NULL)); +} + +static void dnode_free(dnode_t *node, void *context EXT2FS_ATTR((unused))) +{ + free(node); +} + +dnode_t *dnode_create(void *data) +{ + dnode_t *new = malloc(sizeof *new); + if (new) { + new->data = data; + new->parent = NULL; + new->left = NULL; + new->right = NULL; + } + return new; +} + +dnode_t *dnode_init(dnode_t *dnode, void *data) +{ + dnode->data = data; + dnode->parent = NULL; + dnode->left = NULL; + dnode->right = NULL; + return dnode; +} + +void dnode_destroy(dnode_t *dnode) +{ + dict_assert (!dnode_is_in_a_dict(dnode)); + free(dnode); +} + +void *dnode_get(dnode_t *dnode) +{ + return dnode->data; +} + +const void *dnode_getkey(dnode_t *dnode) +{ + return dnode->key; +} + +#ifdef E2FSCK_NOTUSED +void dnode_put(dnode_t *dnode, void *data) +{ + dnode->data = data; +} +#endif + +#ifndef DICT_NODEBUG +int dnode_is_in_a_dict(dnode_t *dnode) +{ + return (dnode->parent && dnode->left && dnode->right); +} +#endif + +#ifdef E2FSCK_NOTUSED +void dict_process(dict_t *dict, void *context, dnode_process_t function) +{ + dnode_t *node = dict_first(dict), *next; + + while (node != NULL) { + /* check for callback function deleting */ + /* the next node from under us */ + dict_assert (dict_contains(dict, node)); + next = dict_next(dict, node); + function(dict, node, context); + node = next; + } +} + +static void load_begin_internal(dict_load_t *load, dict_t *dict) +{ + load->dictptr = dict; + load->nilnode.left = &load->nilnode; + load->nilnode.right = &load->nilnode; +} + +void dict_load_begin(dict_load_t *load, dict_t *dict) +{ + dict_assert (dict_isempty(dict)); + load_begin_internal(load, dict); +} + +void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key) +{ + dict_t *dict = load->dictptr; + dnode_t *nil = &load->nilnode; + + dict_assert (!dnode_is_in_a_dict(newnode)); + dict_assert (dict->nodecount < dict->maxcount); + +#ifndef DICT_NODEBUG + if (dict->nodecount > 0) { + if (dict->dupes) + dict_assert (dict->compare(nil->left->key, key) <= 0); + else + dict_assert (dict->compare(nil->left->key, key) < 0); + } +#endif + + newnode->key = key; + nil->right->left = newnode; + nil->right = newnode; + newnode->left = nil; + dict->nodecount++; +} + +void dict_load_end(dict_load_t *load) +{ + dict_t *dict = load->dictptr; + dnode_t *tree[DICT_DEPTH_MAX] = { 0 }; + dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next; + dnode_t *complete = 0; + dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount; + dictcount_t botrowcount; + unsigned baselevel = 0, level = 0, i; + + dict_assert (dnode_red == 0 && dnode_black == 1); + + while (fullcount >= nodecount && fullcount) + fullcount >>= 1; + + botrowcount = nodecount - fullcount; + + for (curr = loadnil->left; curr != loadnil; curr = next) { + next = curr->left; + + if (complete == NULL && botrowcount-- == 0) { + dict_assert (baselevel == 0); + dict_assert (level == 0); + baselevel = level = 1; + complete = tree[0]; + + if (complete != 0) { + tree[0] = 0; + complete->right = dictnil; + while (tree[level] != 0) { + tree[level]->right = complete; + complete->parent = tree[level]; + complete = tree[level]; + tree[level++] = 0; + } + } + } + + if (complete == NULL) { + curr->left = dictnil; + curr->right = dictnil; + curr->color = level % 2; + complete = curr; + + dict_assert (level == baselevel); + while (tree[level] != 0) { + tree[level]->right = complete; + complete->parent = tree[level]; + complete = tree[level]; + tree[level++] = 0; + } + } else { + curr->left = complete; + curr->color = (level + 1) % 2; + complete->parent = curr; + tree[level] = curr; + complete = 0; + level = baselevel; + } + } + + if (complete == NULL) + complete = dictnil; + + for (i = 0; i < DICT_DEPTH_MAX; i++) { + if (tree[i] != 0) { + tree[i]->right = complete; + complete->parent = tree[i]; + complete = tree[i]; + } + } + + dictnil->color = dnode_black; + dictnil->right = dictnil; + complete->parent = dictnil; + complete->color = dnode_black; + dict_root(dict) = complete; + + dict_assert (dict_verify(dict)); +} + +void dict_merge(dict_t *dest, dict_t *source) +{ + dict_load_t load; + dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source); + + dict_assert (dict_similar(dest, source)); + + if (source == dest) + return; + + dest->nodecount = 0; + load_begin_internal(&load, dest); + + for (;;) { + if (leftnode != NULL && rightnode != NULL) { + if (dest->compare(leftnode->key, rightnode->key) < 0) + goto copyleft; + else + goto copyright; + } else if (leftnode != NULL) { + goto copyleft; + } else if (rightnode != NULL) { + goto copyright; + } else { + dict_assert (leftnode == NULL && rightnode == NULL); + break; + } + + copyleft: + { + dnode_t *next = dict_next(dest, leftnode); +#ifndef DICT_NODEBUG + leftnode->left = NULL; /* suppress assertion in dict_load_next */ +#endif + dict_load_next(&load, leftnode, leftnode->key); + leftnode = next; + continue; + } + + copyright: + { + dnode_t *next = dict_next(source, rightnode); +#ifndef DICT_NODEBUG + rightnode->left = NULL; +#endif + dict_load_next(&load, rightnode, rightnode->key); + rightnode = next; + continue; + } + } + + dict_clear(source); + dict_load_end(&load); +} +#endif /* E2FSCK_NOTUSED */ + +#ifdef KAZLIB_TEST_MAIN + +#include +#include +#include +#include + +typedef char input_t[256]; + +static int tokenize(char *string, ...) +{ + char **tokptr; + va_list arglist; + int tokcount = 0; + + va_start(arglist, string); + tokptr = va_arg(arglist, char **); + while (tokptr) { + while (*string && isspace((unsigned char) *string)) + string++; + if (!*string) + break; + *tokptr = string; + while (*string && !isspace((unsigned char) *string)) + string++; + tokptr = va_arg(arglist, char **); + tokcount++; + if (!*string) + break; + *string++ = 0; + } + va_end(arglist); + + return tokcount; +} + +static int comparef(const void *key1, const void *key2) +{ + return strcmp(key1, key2); +} + +static char *dupstring(char *str) +{ + int sz = strlen(str) + 1; + char *new = malloc(sz); + if (new) + memcpy(new, str, sz); + return new; +} + +static dnode_t *new_node(void *c) +{ + static dnode_t few[5]; + static int count; + + if (count < 5) + return few + count++; + + return NULL; +} + +static void del_node(dnode_t *n, void *c) +{ +} + +static int prompt = 0; + +static void construct(dict_t *d) +{ + input_t in; + int done = 0; + dict_load_t dl; + dnode_t *dn; + char *tok1, *tok2, *val; + const char *key; + char *help = + "p turn prompt on\n" + "q finish construction\n" + "a add new entry\n"; + + if (!dict_isempty(d)) + puts("warning: dictionary not empty!"); + + dict_load_begin(&dl, d); + + while (!done) { + if (prompt) + putchar('>'); + fflush(stdout); + + if (!fgets(in, sizeof(input_t), stdin)) + break; + + switch (in[0]) { + case '?': + puts(help); + break; + case 'p': + prompt = 1; + break; + case 'q': + done = 1; + break; + case 'a': + if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { + puts("what?"); + break; + } + key = dupstring(tok1); + val = dupstring(tok2); + dn = dnode_create(val); + + if (!key || !val || !dn) { + puts("out of memory"); + free((void *) key); + free(val); + if (dn) + dnode_destroy(dn); + } + + dict_load_next(&dl, dn, key); + break; + default: + putchar('?'); + putchar('\n'); + break; + } + } + + dict_load_end(&dl); +} + +int main(void) +{ + input_t in; + dict_t darray[10]; + dict_t *d = &darray[0]; + dnode_t *dn; + int i; + char *tok1, *tok2, *val; + const char *key; + + char *help = + "a add value to dictionary\n" + "d delete value from dictionary\n" + "l lookup value in dictionary\n" + "( lookup lower bound\n" + ") lookup upper bound\n" + "# switch to alternate dictionary (0-9)\n" + "j merge two dictionaries\n" + "f free the whole dictionary\n" + "k allow duplicate keys\n" + "c show number of entries\n" + "t dump whole dictionary in sort order\n" + "m make dictionary out of sorted items\n" + "p turn prompt on\n" + "s switch to non-functioning allocator\n" + "q quit"; + + for (i = 0; i < sizeof darray / sizeof *darray; i++) + dict_init(&darray[i], DICTCOUNT_T_MAX, comparef); + + for (;;) { + if (prompt) + putchar('>'); + fflush(stdout); + + if (!fgets(in, sizeof(input_t), stdin)) + break; + + switch(in[0]) { + case '?': + puts(help); + break; + case 'a': + if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { + puts("what?"); + break; + } + key = dupstring(tok1); + val = dupstring(tok2); + + if (!key || !val) { + puts("out of memory"); + free((void *) key); + free(val); + } + + if (!dict_alloc_insert(d, key, val)) { + puts("dict_alloc_insert failed"); + free((void *) key); + free(val); + break; + } + break; + case 'd': + if (tokenize(in+1, &tok1, (char **) 0) != 1) { + puts("what?"); + break; + } + dn = dict_lookup(d, tok1); + if (!dn) { + puts("dict_lookup failed"); + break; + } + val = dnode_get(dn); + key = dnode_getkey(dn); + dict_delete_free(d, dn); + + free(val); + free((void *) key); + break; + case 'f': + dict_free(d); + break; + case 'l': + case '(': + case ')': + if (tokenize(in+1, &tok1, (char **) 0) != 1) { + puts("what?"); + break; + } + dn = 0; + switch (in[0]) { + case 'l': + dn = dict_lookup(d, tok1); + break; + case '(': + dn = dict_lower_bound(d, tok1); + break; + case ')': + dn = dict_upper_bound(d, tok1); + break; + } + if (!dn) { + puts("lookup failed"); + break; + } + val = dnode_get(dn); + puts(val); + break; + case 'm': + construct(d); + break; + case 'k': + dict_allow_dupes(d); + break; + case 'c': + printf("%lu\n", (unsigned long) dict_count(d)); + break; + case 't': + for (dn = dict_first(d); dn; dn = dict_next(d, dn)) { + printf("%s\t%s\n", (char *) dnode_getkey(dn), + (char *) dnode_get(dn)); + } + break; + case 'q': + exit(0); + break; + case '\0': + break; + case 'p': + prompt = 1; + break; + case 's': + dict_set_allocator(d, new_node, del_node, NULL); + break; + case '#': + if (tokenize(in+1, &tok1, (char **) 0) != 1) { + puts("what?"); + break; + } else { + int dictnum = atoi(tok1); + if (dictnum < 0 || dictnum > 9) { + puts("invalid number"); + break; + } + d = &darray[dictnum]; + } + break; + case 'j': + if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { + puts("what?"); + break; + } else { + int dict1 = atoi(tok1), dict2 = atoi(tok2); + if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) { + puts("invalid number"); + break; + } + dict_merge(&darray[dict1], &darray[dict2]); + } + break; + default: + putchar('?'); + putchar('\n'); + break; + } + } + + return 0; +} + +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/dict.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/dict.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,144 @@ +/* + * Dictionary Abstract Data Type + * Copyright (C) 1997 Kaz Kylheku + * + * Free Software License: + * + * All rights are reserved by the author, with the following exceptions: + * Permission is granted to freely reproduce and distribute this software, + * possibly in exchange for a fee, provided that this copyright notice appears + * intact. Permission is also granted to adapt this software to produce + * derivative works, as long as the modified versions carry this copyright + * notice and additional notices stating that the work has been modified. + * This source code may be translated into executable form and incorporated + * into proprietary software; there is no requirement for such software to + * contain a copyright notice related to this source. + * + * $Id: dict.h,v 1.22.2.6 2000/11/13 01:36:44 kaz Exp $ + * $Name: kazlib_1_20 $ + */ + +#ifndef DICT_H +#define DICT_H + +#include +#ifdef KAZLIB_SIDEEFFECT_DEBUG +#include "sfx.h" +#endif + +/* + * Blurb for inclusion into C++ translation units + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned long dictcount_t; +#define DICTCOUNT_T_MAX ULONG_MAX + +/* + * The dictionary is implemented as a red-black tree + */ + +typedef enum { dnode_red, dnode_black } dnode_color_t; + +typedef struct dnode_t { +#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) + struct dnode_t *dict_left; + struct dnode_t *dict_right; + struct dnode_t *dict_parent; + dnode_color_t dict_color; + const void *dict_key; + void *dict_data; +#else + int dict_dummy; +#endif +} dnode_t; + +typedef int (*dict_comp_t)(const void *, const void *); +typedef dnode_t *(*dnode_alloc_t)(void *); +typedef void (*dnode_free_t)(dnode_t *, void *); + +typedef struct dict_t { +#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) + dnode_t dict_nilnode; + dictcount_t dict_nodecount; + dictcount_t dict_maxcount; + dict_comp_t dict_compare; + dnode_alloc_t dict_allocnode; + dnode_free_t dict_freenode; + void *dict_context; + int dict_dupes; +#else + int dict_dummmy; +#endif +} dict_t; + +typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *); + +typedef struct dict_load_t { +#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) + dict_t *dict_dictptr; + dnode_t dict_nilnode; +#else + int dict_dummmy; +#endif +} dict_load_t; + +extern dict_t *dict_create(dictcount_t, dict_comp_t); +extern void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *); +extern void dict_destroy(dict_t *); +extern void dict_free_nodes(dict_t *); +extern void dict_free(dict_t *); +extern dict_t *dict_init(dict_t *, dictcount_t, dict_comp_t); +extern void dict_init_like(dict_t *, const dict_t *); +extern int dict_verify(dict_t *); +extern int dict_similar(const dict_t *, const dict_t *); +extern dnode_t *dict_lookup(dict_t *, const void *); +extern dnode_t *dict_lower_bound(dict_t *, const void *); +extern dnode_t *dict_upper_bound(dict_t *, const void *); +extern void dict_insert(dict_t *, dnode_t *, const void *); +extern dnode_t *dict_delete(dict_t *, dnode_t *); +extern int dict_alloc_insert(dict_t *, const void *, void *); +extern void dict_delete_free(dict_t *, dnode_t *); +extern dnode_t *dict_first(dict_t *); +extern dnode_t *dict_last(dict_t *); +extern dnode_t *dict_next(dict_t *, dnode_t *); +extern dnode_t *dict_prev(dict_t *, dnode_t *); +extern dictcount_t dict_count(dict_t *); +extern int dict_isempty(dict_t *); +extern int dict_isfull(dict_t *); +extern int dict_contains(dict_t *, dnode_t *); +extern void dict_allow_dupes(dict_t *); +extern int dnode_is_in_a_dict(dnode_t *); +extern dnode_t *dnode_create(void *); +extern dnode_t *dnode_init(dnode_t *, void *); +extern void dnode_destroy(dnode_t *); +extern void *dnode_get(dnode_t *); +extern const void *dnode_getkey(dnode_t *); +extern void dnode_put(dnode_t *, void *); +extern void dict_process(dict_t *, void *, dnode_process_t); +extern void dict_load_begin(dict_load_t *, dict_t *); +extern void dict_load_next(dict_load_t *, dnode_t *, const void *); +extern void dict_load_end(dict_load_t *); +extern void dict_merge(dict_t *, dict_t *); + +#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) +#ifdef KAZLIB_SIDEEFFECT_DEBUG +#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount) +#else +#define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount) +#endif +#define dict_count(D) ((D)->dict_nodecount) +#define dict_isempty(D) ((D)->dict_nodecount == 0) +#define dnode_get(N) ((N)->dict_data) +#define dnode_getkey(N) ((N)->dict_key) +#define dnode_put(N, X) ((N)->dict_data = (X)) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/dqblk_v2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/dqblk_v2.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,31 @@ +/* + * Header file for disk format of new quotafile format + * + * Jan Kara - sponsored by SuSE CR + */ + +#ifndef __QUOTA_DQBLK_V2_H__ +#define __QUOTA_DQBLK_V2_H__ + +#include "quotaio_tree.h" + +/* Structure for format specific information */ +struct v2_mem_dqinfo { + struct qtree_mem_dqinfo dqi_qtree; + unsigned int dqi_flags; /* Flags set in quotafile */ + unsigned int dqi_used_entries; /* Number of entries in file - + updated by scan_dquots */ + unsigned int dqi_data_blocks; /* Number of data blocks in file - + updated by scan_dquots */ +}; + +struct v2_mem_dqblk { + long long dqb_off; /* Offset of dquot in file */ +}; + +struct quotafile_ops; /* Will be defined later in quotaio.h */ + +/* Operations above this format */ +extern struct quotafile_ops quotafile_ops_2; + +#endif /* __QUOTA_DQBLK_V2_H__ */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/mkquota.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/mkquota.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,727 @@ +/* + * mkquota.c --- create quota files for a filesystem + * + * Aditya Kali + */ +#include "config.h" +#include +#include +#include +#include +#include +#include + +#include "ext2fs/ext2_fs.h" +#include "ext2fs/ext2fs.h" +#include "e2p/e2p.h" + +#include "quotaio.h" +#include "quotaio_v2.h" +#include "quotaio_tree.h" +#include "common.h" +#include "dict.h" + +/* Needed for architectures where sizeof(int) != sizeof(void *) */ +#define UINT_TO_VOIDPTR(val) ((void *)(intptr_t)(val)) +#define VOIDPTR_TO_UINT(ptr) ((unsigned int)(intptr_t)(ptr)) + +#if DEBUG_QUOTA +static void print_inode(struct ext2_inode *inode) +{ + if (!inode) + return; + + fprintf(stderr, " i_mode = %d\n", inode->i_mode); + fprintf(stderr, " i_uid = %d\n", inode->i_uid); + fprintf(stderr, " i_size = %d\n", inode->i_size); + fprintf(stderr, " i_atime = %d\n", inode->i_atime); + fprintf(stderr, " i_ctime = %d\n", inode->i_ctime); + fprintf(stderr, " i_mtime = %d\n", inode->i_mtime); + fprintf(stderr, " i_dtime = %d\n", inode->i_dtime); + fprintf(stderr, " i_gid = %d\n", inode->i_gid); + fprintf(stderr, " i_links_count = %d\n", inode->i_links_count); + fprintf(stderr, " i_blocks = %d\n", inode->i_blocks); + fprintf(stderr, " i_flags = %d\n", inode->i_flags); + + return; +} + +static void print_dquot(const char *desc, struct dquot *dq) +{ + if (desc) + fprintf(stderr, "%s: ", desc); + fprintf(stderr, "%u %lld:%lld:%lld %lld:%lld:%lld\n", + dq->dq_id, (long long) dq->dq_dqb.dqb_curspace, + (long long) dq->dq_dqb.dqb_bsoftlimit, + (long long) dq->dq_dqb.dqb_bhardlimit, + (long long) dq->dq_dqb.dqb_curinodes, + (long long) dq->dq_dqb.dqb_isoftlimit, + (long long) dq->dq_dqb.dqb_ihardlimit); +} +#else +static void print_dquot(const char *desc EXT2FS_ATTR((unused)), + struct dquot *dq EXT2FS_ATTR((unused))) +{ +} +#endif + +/* + * Returns 0 if not able to find the quota file, otherwise returns its + * inode number. + */ +int quota_file_exists(ext2_filsys fs, enum quota_type qtype) +{ + char qf_name[256]; + errcode_t ret; + ext2_ino_t ino; + + if (qtype >= MAXQUOTAS) + return -EINVAL; + + quota_get_qf_name(qtype, QFMT_VFS_V1, qf_name); + + ret = ext2fs_lookup(fs, EXT2_ROOT_INO, qf_name, strlen(qf_name), 0, + &ino); + if (ret) + return 0; + + return ino; +} + +/* + * Set the value for reserved quota inode number field in superblock. + */ +void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, enum quota_type qtype) +{ + ext2_ino_t *inump; + + inump = quota_sb_inump(fs->super, qtype); + + log_debug("setting quota ino in superblock: ino=%u, type=%d", ino, + qtype); + *inump = ino; + ext2fs_mark_super_dirty(fs); +} + +errcode_t quota_remove_inode(ext2_filsys fs, enum quota_type qtype) +{ + ext2_ino_t qf_ino; + errcode_t retval; + + retval = ext2fs_read_bitmaps(fs); + if (retval) { + log_debug("Couldn't read bitmaps: %s", error_message(retval)); + return retval; + } + + qf_ino = *quota_sb_inump(fs->super, qtype); + if (qf_ino == 0) + return 0; + retval = quota_inode_truncate(fs, qf_ino); + if (retval) + return retval; + if (qf_ino >= EXT2_FIRST_INODE(fs->super)) { + struct ext2_inode inode; + + retval = ext2fs_read_inode(fs, qf_ino, &inode); + if (!retval) { + memset(&inode, 0, sizeof(struct ext2_inode)); + ext2fs_write_inode(fs, qf_ino, &inode); + } + ext2fs_inode_alloc_stats2(fs, qf_ino, -1, 0); + ext2fs_mark_ib_dirty(fs); + + } + quota_set_sb_inum(fs, 0, qtype); + + ext2fs_mark_super_dirty(fs); + fs->flags &= ~EXT2_FLAG_SUPER_ONLY; + retval = ext2fs_write_bitmaps(fs); + if (retval) { + log_debug("Couldn't write bitmaps: %s", error_message(retval)); + return retval; + } + return 0; +} + +static void write_dquots(dict_t *dict, struct quota_handle *qh) +{ + dnode_t *n; + struct dquot *dq; + + for (n = dict_first(dict); n; n = dict_next(dict, n)) { + dq = dnode_get(n); + if (dq) { + print_dquot("write", dq); + dq->dq_h = qh; + update_grace_times(dq); + qh->qh_ops->commit_dquot(dq); + } + } +} + +errcode_t quota_write_inode(quota_ctx_t qctx, unsigned int qtype_bits) +{ + int retval = 0; + enum quota_type qtype; + dict_t *dict; + ext2_filsys fs; + struct quota_handle *h = NULL; + int fmt = QFMT_VFS_V1; + + if (!qctx) + return 0; + + fs = qctx->fs; + retval = ext2fs_get_mem(sizeof(struct quota_handle), &h); + if (retval) { + log_debug("Unable to allocate quota handle: %s", + error_message(retval)); + goto out; + } + + retval = ext2fs_read_bitmaps(fs); + if (retval) { + log_debug("Couldn't read bitmaps: %s", error_message(retval)); + goto out; + } + + for (qtype = 0; qtype < MAXQUOTAS; qtype++) { + if (((1 << qtype) & qtype_bits) == 0) + continue; + + dict = qctx->quota_dict[qtype]; + if (!dict) + continue; + + retval = quota_file_create(h, fs, qtype, fmt); + if (retval) { + log_debug("Cannot initialize io on quotafile: %s", + error_message(retval)); + goto out; + } + + write_dquots(dict, h); + retval = quota_file_close(qctx, h); + if (retval) { + log_debug("Cannot finish IO on new quotafile: %s", + strerror(errno)); + if (h->qh_qf.e2_file) + ext2fs_file_close(h->qh_qf.e2_file); + (void) quota_inode_truncate(fs, h->qh_qf.ino); + goto out; + } + + /* Set quota inode numbers in superblock. */ + quota_set_sb_inum(fs, h->qh_qf.ino, qtype); + ext2fs_mark_super_dirty(fs); + ext2fs_mark_bb_dirty(fs); + fs->flags &= ~EXT2_FLAG_SUPER_ONLY; + } + + retval = ext2fs_write_bitmaps(fs); + if (retval) { + log_debug("Couldn't write bitmaps: %s", error_message(retval)); + goto out; + } +out: + if (h) + ext2fs_free_mem(&h); + return retval; +} + +/******************************************************************/ +/* Helper functions for computing quota in memory. */ +/******************************************************************/ + +static int dict_uint_cmp(const void *a, const void *b) +{ + unsigned int c, d; + + c = VOIDPTR_TO_UINT(a); + d = VOIDPTR_TO_UINT(b); + + if (c == d) + return 0; + else if (c > d) + return 1; + else + return -1; +} + +static inline int project_quota_valid(quota_ctx_t qctx) +{ + return (EXT2_INODE_SIZE(qctx->fs->super) > EXT2_GOOD_OLD_INODE_SIZE); +} + +static inline qid_t get_qid(struct ext2_inode_large *inode, enum quota_type qtype) +{ + unsigned int inode_size; + + switch (qtype) { + case USRQUOTA: + return inode_uid(*inode); + case GRPQUOTA: + return inode_gid(*inode); + case PRJQUOTA: + inode_size = EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize; + if (inode_includes(inode_size, i_projid)) + return inode_projid(*inode); + return 0; + default: + return 0; + } + + return 0; +} + +static void quota_dnode_free(dnode_t *node, + void *context EXT2FS_ATTR((unused))) +{ + void *ptr = node ? dnode_get(node) : 0; + + ext2fs_free_mem(&ptr); + free(node); +} + +/* + * Set up the quota tracking data structures. + */ +errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, + unsigned int qtype_bits) +{ + errcode_t err; + dict_t *dict; + quota_ctx_t ctx; + enum quota_type qtype; + + err = ext2fs_get_mem(sizeof(struct quota_ctx), &ctx); + if (err) { + log_debug("Failed to allocate quota context"); + return err; + } + + memset(ctx, 0, sizeof(struct quota_ctx)); + for (qtype = 0; qtype < MAXQUOTAS; qtype++) { + ctx->quota_file[qtype] = NULL; + if (qtype_bits) { + if (((1 << qtype) & qtype_bits) == 0) + continue; + } else { + if (*quota_sb_inump(fs->super, qtype) == 0) + continue; + } + err = ext2fs_get_mem(sizeof(dict_t), &dict); + if (err) { + log_debug("Failed to allocate dictionary"); + quota_release_context(&ctx); + return err; + } + ctx->quota_dict[qtype] = dict; + dict_init(dict, DICTCOUNT_T_MAX, dict_uint_cmp); + dict_set_allocator(dict, NULL, quota_dnode_free, NULL); + } + + ctx->fs = fs; + *qctx = ctx; + return 0; +} + +void quota_release_context(quota_ctx_t *qctx) +{ + errcode_t err; + dict_t *dict; + enum quota_type qtype; + quota_ctx_t ctx; + + if (!qctx) + return; + + ctx = *qctx; + for (qtype = 0; qtype < MAXQUOTAS; qtype++) { + dict = ctx->quota_dict[qtype]; + ctx->quota_dict[qtype] = 0; + if (dict) { + dict_free_nodes(dict); + free(dict); + } + if (ctx->quota_file[qtype]) { + err = quota_file_close(ctx, ctx->quota_file[qtype]); + if (err) { + log_err("Cannot close quotafile: %s", + strerror(errno)); + ext2fs_free_mem(&ctx->quota_file[qtype]); + } + } + } + *qctx = NULL; + free(ctx); +} + +static struct dquot *get_dq(dict_t *dict, __u32 key) +{ + struct dquot *dq; + dnode_t *n; + + n = dict_lookup(dict, UINT_TO_VOIDPTR(key)); + if (n) + dq = dnode_get(n); + else { + if (ext2fs_get_mem(sizeof(struct dquot), &dq)) { + log_err("Unable to allocate dquot"); + return NULL; + } + memset(dq, 0, sizeof(struct dquot)); + dict_alloc_insert(dict, UINT_TO_VOIDPTR(key), dq); + dq->dq_id = key; + } + return dq; +} + + +/* + * Called to update the blocks used by a particular inode + */ +void quota_data_add(quota_ctx_t qctx, struct ext2_inode_large *inode, + ext2_ino_t ino EXT2FS_ATTR((unused)), + qsize_t space) +{ + struct dquot *dq; + dict_t *dict; + enum quota_type qtype; + + if (!qctx) + return; + + log_debug("ADD_DATA: Inode: %u, UID/GID: %u/%u, space: %ld", ino, + inode_uid(*inode), + inode_gid(*inode), space); + for (qtype = 0; qtype < MAXQUOTAS; qtype++) { + if (qtype == PRJQUOTA && !project_quota_valid(qctx)) + continue; + dict = qctx->quota_dict[qtype]; + if (dict) { + dq = get_dq(dict, get_qid(inode, qtype)); + if (dq) + dq->dq_dqb.dqb_curspace += space; + } + } +} + +/* + * Called to remove some blocks used by a particular inode + */ +void quota_data_sub(quota_ctx_t qctx, struct ext2_inode_large *inode, + ext2_ino_t ino EXT2FS_ATTR((unused)), + qsize_t space) +{ + struct dquot *dq; + dict_t *dict; + enum quota_type qtype; + + if (!qctx) + return; + + log_debug("SUB_DATA: Inode: %u, UID/GID: %u/%u, space: %ld", ino, + inode_uid(*inode), + inode_gid(*inode), space); + for (qtype = 0; qtype < MAXQUOTAS; qtype++) { + if (qtype == PRJQUOTA && !project_quota_valid(qctx)) + continue; + dict = qctx->quota_dict[qtype]; + if (dict) { + dq = get_dq(dict, get_qid(inode, qtype)); + dq->dq_dqb.dqb_curspace -= space; + } + } +} + +/* + * Called to count the files used by an inode's user/group + */ +void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode_large *inode, + ext2_ino_t ino EXT2FS_ATTR((unused)), int adjust) +{ + struct dquot *dq; + dict_t *dict; + enum quota_type qtype; + + if (!qctx) + return; + + log_debug("ADJ_INODE: Inode: %u, UID/GID: %u/%u, adjust: %d", ino, + inode_uid(*inode), + inode_gid(*inode), adjust); + for (qtype = 0; qtype < MAXQUOTAS; qtype++) { + if (qtype == PRJQUOTA && !project_quota_valid(qctx)) + continue; + dict = qctx->quota_dict[qtype]; + if (dict) { + dq = get_dq(dict, get_qid(inode, qtype)); + dq->dq_dqb.dqb_curinodes += adjust; + } + } +} + +errcode_t quota_compute_usage(quota_ctx_t qctx) +{ + ext2_filsys fs; + ext2_ino_t ino; + errcode_t ret; + struct ext2_inode_large *inode; + int inode_size; + qsize_t space; + ext2_inode_scan scan; + + if (!qctx) + return 0; + + fs = qctx->fs; + ret = ext2fs_open_inode_scan(fs, 0, &scan); + if (ret) { + log_err("while opening inode scan. ret=%ld", ret); + return ret; + } + inode_size = fs->super->s_inode_size; + inode = malloc(inode_size); + if (!inode) { + ext2fs_close_inode_scan(scan); + return ENOMEM; + } + while (1) { + ret = ext2fs_get_next_inode_full(scan, &ino, + EXT2_INODE(inode), inode_size); + if (ret) { + log_err("while getting next inode. ret=%ld", ret); + ext2fs_close_inode_scan(scan); + free(inode); + return ret; + } + if (ino == 0) + break; + if (inode->i_links_count && + (ino == EXT2_ROOT_INO || + ino >= EXT2_FIRST_INODE(fs->super))) { + space = ext2fs_inode_i_blocks(fs, + EXT2_INODE(inode)) << 9; + quota_data_add(qctx, inode, ino, space); + quota_data_inodes(qctx, inode, ino, +1); + } + } + + ext2fs_close_inode_scan(scan); + free(inode); + return 0; +} + +struct scan_dquots_data { + dict_t *quota_dict; + int update_limits; /* update limits from disk */ + int update_usage; + int check_consistency; + int usage_is_inconsistent; +}; + +static int scan_dquots_callback(struct dquot *dquot, void *cb_data) +{ + struct scan_dquots_data *scan_data = cb_data; + dict_t *quota_dict = scan_data->quota_dict; + struct dquot *dq; + + dq = get_dq(quota_dict, dquot->dq_id); + dq->dq_id = dquot->dq_id; + dq->dq_flags |= DQF_SEEN; + + print_dquot("mem", dq); + print_dquot("dsk", dquot); + + /* Check if there is inconsistency */ + if (scan_data->check_consistency && + (dq->dq_dqb.dqb_curspace != dquot->dq_dqb.dqb_curspace || + dq->dq_dqb.dqb_curinodes != dquot->dq_dqb.dqb_curinodes)) { + scan_data->usage_is_inconsistent = 1; + fprintf(stderr, "[QUOTA WARNING] Usage inconsistent for ID %u:" + "actual (%lld, %lld) != expected (%lld, %lld)\n", + dq->dq_id, (long long) dq->dq_dqb.dqb_curspace, + (long long) dq->dq_dqb.dqb_curinodes, + (long long) dquot->dq_dqb.dqb_curspace, + (long long) dquot->dq_dqb.dqb_curinodes); + } + + if (scan_data->update_limits) { + dq->dq_dqb.dqb_ihardlimit = dquot->dq_dqb.dqb_ihardlimit; + dq->dq_dqb.dqb_isoftlimit = dquot->dq_dqb.dqb_isoftlimit; + dq->dq_dqb.dqb_bhardlimit = dquot->dq_dqb.dqb_bhardlimit; + dq->dq_dqb.dqb_bsoftlimit = dquot->dq_dqb.dqb_bsoftlimit; + } + + if (scan_data->update_usage) { + dq->dq_dqb.dqb_curspace = dquot->dq_dqb.dqb_curspace; + dq->dq_dqb.dqb_curinodes = dquot->dq_dqb.dqb_curinodes; + } + + return 0; +} + +/* + * Read all dquots from quota file into memory + */ +static errcode_t quota_read_all_dquots(struct quota_handle *qh, + quota_ctx_t qctx, + int update_limits EXT2FS_ATTR((unused))) +{ + struct scan_dquots_data scan_data; + + scan_data.quota_dict = qctx->quota_dict[qh->qh_type]; + scan_data.check_consistency = 0; + scan_data.update_limits = 0; + scan_data.update_usage = 1; + + return qh->qh_ops->scan_dquots(qh, scan_dquots_callback, &scan_data); +} + +/* + * Write all memory dquots into quota file + */ +#if 0 /* currently unused, but may be useful in the future? */ +static errcode_t quota_write_all_dquots(struct quota_handle *qh, + quota_ctx_t qctx) +{ + errcode_t err; + + err = ext2fs_read_bitmaps(qctx->fs); + if (err) + return err; + write_dquots(qctx->quota_dict[qh->qh_type], qh); + ext2fs_mark_bb_dirty(qctx->fs); + qctx->fs->flags &= ~EXT2_FLAG_SUPER_ONLY; + ext2fs_write_bitmaps(qctx->fs); + return 0; +} +#endif + +/* + * Updates the in-memory quota limits from the given quota inode. + */ +errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, + enum quota_type qtype) +{ + struct quota_handle *qh; + errcode_t err; + + if (!qctx) + return 0; + + err = ext2fs_get_mem(sizeof(struct quota_handle), &qh); + if (err) { + log_debug("Unable to allocate quota handle"); + return err; + } + + err = quota_file_open(qctx, qh, qf_ino, qtype, -1, 0); + if (err) { + log_debug("Open quota file failed"); + goto out; + } + + quota_read_all_dquots(qh, qctx, 1); + + err = quota_file_close(qctx, qh); + if (err) { + log_debug("Cannot finish IO on new quotafile: %s", + strerror(errno)); + if (qh->qh_qf.e2_file) + ext2fs_file_close(qh->qh_qf.e2_file); + } +out: + ext2fs_free_mem(&qh); + return err; +} + +/* + * Compares the measured quota in qctx->quota_dict with that in the quota inode + * on disk and updates the limits in qctx->quota_dict. 'usage_inconsistent' is + * set to 1 if the supplied and on-disk quota usage values are not identical. + */ +errcode_t quota_compare_and_update(quota_ctx_t qctx, enum quota_type qtype, + int *usage_inconsistent) +{ + struct quota_handle qh; + struct scan_dquots_data scan_data; + struct dquot *dq; + dnode_t *n; + dict_t *dict = qctx->quota_dict[qtype]; + errcode_t err = 0; + + if (!dict) + goto out; + + err = quota_file_open(qctx, &qh, 0, qtype, -1, 0); + if (err) { + log_debug("Open quota file failed"); + goto out; + } + + scan_data.quota_dict = qctx->quota_dict[qtype]; + scan_data.update_limits = 1; + scan_data.update_usage = 0; + scan_data.check_consistency = 1; + scan_data.usage_is_inconsistent = 0; + err = qh.qh_ops->scan_dquots(&qh, scan_dquots_callback, &scan_data); + if (err) { + log_debug("Error scanning dquots"); + goto out_close_qh; + } + + for (n = dict_first(dict); n; n = dict_next(dict, n)) { + dq = dnode_get(n); + if (!dq) + continue; + if ((dq->dq_flags & DQF_SEEN) == 0) { + fprintf(stderr, "[QUOTA WARNING] " + "Missing quota entry ID %d\n", dq->dq_id); + scan_data.usage_is_inconsistent = 1; + } + } + *usage_inconsistent = scan_data.usage_is_inconsistent; + +out_close_qh: + err = quota_file_close(qctx, &qh); + if (err) { + log_debug("Cannot close quotafile: %s", error_message(errno)); + if (qh.qh_qf.e2_file) + ext2fs_file_close(qh.qh_qf.e2_file); + } +out: + return err; +} + +int parse_quota_opts(const char *opts, int (*func)(char *)) +{ + char *buf, *token, *next, *p; + int len; + int ret = 0; + + len = strlen(opts); + buf = malloc(len + 1); + if (!buf) { + fprintf(stderr, + "Couldn't allocate memory to parse quota options!\n"); + return -ENOMEM; + } + strcpy(buf, opts); + for (token = buf; token && *token; token = next) { + p = strchr(token, ','); + next = 0; + if (p) { + *p = 0; + next = p + 1; + } + ret = func(token); + if (ret) + break; + } + free(buf); + return ret; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/nls-enable.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/nls-enable.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,21 @@ +#if defined(ENABLE_NLS) && !defined(DEBUGFS) +#include +#include +#define _(a) (gettext (a)) +#ifdef gettext_noop +#define N_(a) gettext_noop (a) +#else +#define N_(a) (a) +#endif +#define P_(singular, plural, n) (ngettext (singular, plural, n)) +#ifndef NLS_CAT_NAME +#define NLS_CAT_NAME "e2fsprogs" +#endif +#ifndef LOCALEDIR +#define LOCALEDIR "/usr/share/locale" +#endif +#else +#define _(a) (a) +#define N_(a) a +#define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural)) +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/parse_qtype.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/parse_qtype.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,90 @@ +/* + * parse_qtype.c + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include + +#include "quotaio.h" + +#define PARSE_DELIM ":," + +int parse_quota_types(const char *in_str, unsigned int *qtype_bits, + char **err_token) +{ + char *buf, *token, *next, *tmp; + unsigned int qtype = *qtype_bits; + int len, ret = 0; + + if (!in_str) + return 0; + + len = strlen(in_str); + buf = malloc(len + 1); + if (!buf) + return ENOMEM; + strcpy(buf, in_str); + + for (token = buf, next = strtok_r(buf, PARSE_DELIM, &tmp); + token && *token; token = next) { + int not = 0; + char *p = token; + + if (*p == '^') { + not = 1; + p++; + } + if (!strcmp(p, "usr") || !strcmp(p, "usrquota")) { + if (not) + qtype &= ~QUOTA_USR_BIT; + else + qtype |= QUOTA_USR_BIT; + } else if (!strcmp(p, "grp") || !strcmp(p, "grpquota")) { + if (not) + qtype &= ~QUOTA_GRP_BIT; + else + qtype |= QUOTA_GRP_BIT; + } else if (!strcmp(p, "prj") || !strcmp(p, "prjquota")) { + if (not) + qtype &= ~QUOTA_PRJ_BIT; + else + qtype |= QUOTA_PRJ_BIT; + } else { + if (err_token) { + *err_token = malloc(strlen(token) + 1); + if (*err_token) + strcpy(*err_token, token); + } + ret = EINVAL; + goto errout; + } +#ifdef DEBUG_PROGRAM + printf("word: %s\n", token); +#endif + next = strtok_r(NULL, PARSE_DELIM, &tmp); + } + *qtype_bits = qtype; +errout: + free(buf); + return ret; +} + +#ifdef DEBUG_PROGRAM +int main(int argc, char **argv) +{ + unsigned int qtype_bits = 0; + int ret; + char *err_token = 0; + + ret = parse_quota_types(argv[1], &qtype_bits, &err_token); + printf("parse_quota_types returns %d, %d\n", ret, qtype_bits); + if (err_token) + printf("err_token is %s\n", err_token); + return 0; +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/plausible.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/plausible.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,291 @@ +/* + * plausible.c --- Figure out if a pathname is ext* or something else. + * + * Copyright 2014, Oracle, Inc. + * + * Some parts are: + * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#include "config.h" +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_MAGIC_H +#include +#endif +#include "plausible.h" +#include "ext2fs/ext2fs.h" +#include "nls-enable.h" +#include "blkid/blkid.h" + +#ifdef HAVE_MAGIC_H +static magic_t (*dl_magic_open)(int); +static const char *(*dl_magic_file)(magic_t, const char *); +static int (*dl_magic_load)(magic_t, const char *); +static void (*dl_magic_close)(magic_t); + +/* + * NO_CHECK functionality was only added in file 4.20. + * Older systems like RHEL 5.x still have file 4.17 + */ +#ifndef MAGIC_NO_CHECK_COMPRESS +#define MAGIC_NO_CHECK_COMPRESS 0x0001000 +#endif +#ifndef MAGIC_NO_CHECK_ELF +#define MAGIC_NO_CHECK_ELF 0x0010000 +#endif + +#ifdef HAVE_DLOPEN +#include + +static void *magic_handle; + +static int magic_library_available(void) +{ + if (!magic_handle) { + magic_handle = dlopen("libmagic.so.1", RTLD_NOW); + if (!magic_handle) + return 0; + + dl_magic_open = (magic_t (*)(int)) + dlsym(magic_handle, "magic_open"); + dl_magic_file = (const char *(*)(magic_t, const char *)) + dlsym(magic_handle, "magic_file"); + dl_magic_load = (int (*)(magic_t, const char *)) + dlsym(magic_handle, "magic_load"); + dl_magic_close = (void (*)(magic_t)) + dlsym(magic_handle, "magic_close"); + } + + if (!dl_magic_open || !dl_magic_file || + !dl_magic_load || !dl_magic_close) + return 0; + return 1; +} +#else +static int magic_library_available(void) +{ + dl_magic_open = magic_open; + dl_magic_file = magic_file; + dl_magic_load = magic_load; + dl_magic_close = magic_close; + + return 1; +} +#endif +#endif + +static void print_ext2_info(const char *device) + +{ + struct ext2_super_block *sb; + ext2_filsys fs; + errcode_t retval; + time_t tm; + char buf[80]; + + retval = ext2fs_open2(device, 0, EXT2_FLAG_64BITS, 0, 0, + unix_io_manager, &fs); + if (retval) + return; + sb = fs->super; + + if (sb->s_mtime) { + tm = sb->s_mtime; + if (sb->s_last_mounted[0]) { + memset(buf, 0, sizeof(buf)); + strncpy(buf, sb->s_last_mounted, + sizeof(sb->s_last_mounted)); + printf(_("\tlast mounted on %s on %s"), buf, + ctime(&tm)); + } else + printf(_("\tlast mounted on %s"), ctime(&tm)); + } else if (sb->s_mkfs_time) { + tm = sb->s_mkfs_time; + printf(_("\tcreated on %s"), ctime(&tm)); + } else if (sb->s_wtime) { + tm = sb->s_wtime; + printf(_("\tlast modified on %s"), ctime(&tm)); + } + ext2fs_close_free(&fs); +} + +/* + * return 1 if there is no partition table, 0 if a partition table is + * detected, and -1 on an error. + */ +#ifdef HAVE_BLKID_PROBE_ENABLE_PARTITIONS +static int check_partition_table(const char *device) +{ + blkid_probe pr; + const char *value; + int ret; + + pr = blkid_new_probe_from_filename(device); + if (!pr) + return -1; + + ret = blkid_probe_enable_partitions(pr, 1); + if (ret < 0) + goto errout; + + ret = blkid_probe_enable_superblocks(pr, 0); + if (ret < 0) + goto errout; + + ret = blkid_do_fullprobe(pr); + if (ret < 0) + goto errout; + + ret = blkid_probe_lookup_value(pr, "PTTYPE", &value, NULL); + if (ret == 0) + fprintf(stderr, _("Found a %s partition table in %s\n"), + value, device); + else + ret = 1; + +errout: + blkid_free_probe(pr); + return ret; +} +#else +static int check_partition_table(const char *device EXT2FS_ATTR((unused))) +{ + return -1; +} +#endif + +/* + * return 1 if the device looks plausible, creating the file if necessary + */ +int check_plausibility(const char *device, int flags, int *ret_is_dev) +{ + int fd, ret, is_dev = 0; + ext2fs_struct_stat s; + int fl = O_RDONLY; + blkid_cache cache = NULL; + char *fs_type = NULL; + char *fs_label = NULL; + + fd = ext2fs_open_file(device, fl, 0666); + if ((fd < 0) && (errno == ENOENT) && (flags & NO_SIZE)) { + fprintf(stderr, _("The file %s does not exist and no " + "size was specified.\n"), device); + exit(1); + } + if ((fd < 0) && (errno == ENOENT) && (flags & CREATE_FILE)) { + fl |= O_CREAT; + fd = ext2fs_open_file(device, fl, 0666); + if (fd >= 0 && (flags & VERBOSE_CREATE)) + printf(_("Creating regular file %s\n"), device); + } + if (fd < 0) { + fprintf(stderr, _("Could not open %s: %s\n"), + device, error_message(errno)); + if (errno == ENOENT) + fputs(_("\nThe device apparently does not exist; " + "did you specify it correctly?\n"), stderr); + exit(1); + } + + if (ext2fs_fstat(fd, &s) < 0) { + perror("stat"); + exit(1); + } + close(fd); + + if (S_ISBLK(s.st_mode)) + is_dev = 1; +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + /* On FreeBSD, all disk devices are character specials */ + if (S_ISCHR(s.st_mode)) + is_dev = 1; +#endif + if (ret_is_dev) + *ret_is_dev = is_dev; + + if ((flags & CHECK_BLOCK_DEV) && !is_dev) { + printf(_("%s is not a block special device.\n"), device); + return 0; + } + + /* + * Note: we use the older-style blkid API's here because we + * want as much functionality to be available when using the + * internal blkid library, when e2fsprogs is compiled for + * non-Linux systems that will probably not have the libraries + * from util-linux available. We only use the newer + * blkid-probe interfaces to access functionality not + * available in the original blkid library. + */ + if ((flags & CHECK_FS_EXIST) && blkid_get_cache(&cache, NULL) >= 0) { + fs_type = blkid_get_tag_value(cache, "TYPE", device); + if (fs_type) + fs_label = blkid_get_tag_value(cache, "LABEL", device); + blkid_put_cache(cache); + } + + if (fs_type) { + if (fs_label) + printf(_("%s contains a %s file system labelled '%s'\n"), + device, fs_type, fs_label); + else + printf(_("%s contains a %s file system\n"), device, + fs_type); + if (strncmp(fs_type, "ext", 3) == 0) + print_ext2_info(device); + free(fs_type); + free(fs_label); + return 0; + } + +#ifdef HAVE_MAGIC_H + if ((flags & CHECK_FS_EXIST) && + !getenv("E2FSPROGS_LIBMAGIC_SUPPRESS") && + magic_library_available()) { + const char *msg; + magic_t mag; + int has_magic = 0; + + mag = dl_magic_open(MAGIC_RAW | MAGIC_SYMLINK | MAGIC_DEVICES | + MAGIC_ERROR | MAGIC_NO_CHECK_ELF | + MAGIC_NO_CHECK_COMPRESS); + dl_magic_load(mag, NULL); + + msg = dl_magic_file(mag, device); + if (msg && strcmp(msg, "data") && strcmp(msg, "empty")) { + printf(_("%s contains `%s' data\n"), device, msg); + has_magic = 1; + } + + dl_magic_close(mag); + return !has_magic; + } +#endif + + ret = check_partition_table(device); + if (ret >= 0) + return ret; + + return 1; +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/plausible.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/plausible.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,29 @@ +/* + * plausible.h --- header file defining prototypes for helper functions + * used by tune2fs and mke2fs + * + * Copyright 2014 by Oracle, Inc. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#ifndef PLAUSIBLE_H_ +#define PLAUSIBLE_H_ + +/* + * Flags for check_plausibility() + */ +#define CHECK_BLOCK_DEV 0x0001 +#define CREATE_FILE 0x0002 +#define CHECK_FS_EXIST 0x0004 +#define VERBOSE_CREATE 0x0008 +#define NO_SIZE 0x0010 +#define QUIET_CHECK 0x0020 + +extern int check_plausibility(const char *device, int flags, + int *ret_is_dev); + +#endif /* PLAUSIBLE_H_ */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/prof_err.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/prof_err.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,85 @@ +/* + * prof_err.c: + * This file is automatically generated; please do not edit it. + */ + +#include + +#define N_(a) a + +static const char * const text[] = { + N_("Profile version 0.0"), + N_("Bad magic value in profile_node"), + N_("Profile section not found"), + N_("Profile relation not found"), + N_( "Attempt to add a relation to node which is not a section"), + N_( "A profile section header has a non-zero value"), + N_("Bad linked list in profile structures"), + N_("Bad group level in profile structures"), + N_( "Bad parent pointer in profile structures"), + N_("Bad magic value in profile iterator"), + N_("Can't set value on section node"), + N_("Invalid argument passed to profile library"), + N_("Attempt to modify read-only profile"), + N_("Profile section header not at top level"), + N_("Syntax error in profile section header"), + N_("Syntax error in profile relation"), + N_("Extra closing brace in profile"), + N_("Missing open brace in profile"), + N_("Bad magic value in profile_t"), + N_("Bad magic value in profile_section_t"), + N_( "Iteration through all top level section not supported"), + N_("Invalid profile_section object"), + N_("No more sections"), + N_("Bad nameset passed to query routine"), + N_("No profile file open"), + N_("Bad magic value in profile_file_t"), + N_("Couldn't open profile file"), + N_("Section already exists"), + N_("Invalid boolean value"), + N_("Invalid integer value"), + N_("Bad magic value in profile_file_data_t"), + 0 +}; + +struct error_table { + char const * const * msgs; + long base; + int n_msgs; +}; +struct et_list { + struct et_list *next; + const struct error_table * table; +}; +extern struct et_list *_et_list; + +const struct error_table et_prof_error_table = { text, -1429577728L, 31 }; + +static struct et_list link = { 0, 0 }; + +void initialize_prof_error_table_r(struct et_list **list); +void initialize_prof_error_table(void); + +void initialize_prof_error_table(void) { + initialize_prof_error_table_r(&_et_list); +} + +/* For Heimdal compatibility */ +void initialize_prof_error_table_r(struct et_list **list) +{ + struct et_list *et, **end; + + for (end = list, et = *list; et; end = &et->next, et = et->next) + if (et->table->msgs == text) + return; + et = malloc(sizeof(struct et_list)); + if (et == 0) { + if (!link.table) + et = &link; + else + return; + } + et->table = &et_prof_error_table; + et->next = 0; + *end = et; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/prof_err.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/prof_err.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,49 @@ +/* + * prof_err.h: + * This file is automatically generated; please do not edit it. + */ + +#include + +#define PROF_VERSION (-1429577728L) +#define PROF_MAGIC_NODE (-1429577727L) +#define PROF_NO_SECTION (-1429577726L) +#define PROF_NO_RELATION (-1429577725L) +#define PROF_ADD_NOT_SECTION (-1429577724L) +#define PROF_SECTION_WITH_VALUE (-1429577723L) +#define PROF_BAD_LINK_LIST (-1429577722L) +#define PROF_BAD_GROUP_LVL (-1429577721L) +#define PROF_BAD_PARENT_PTR (-1429577720L) +#define PROF_MAGIC_ITERATOR (-1429577719L) +#define PROF_SET_SECTION_VALUE (-1429577718L) +#define PROF_EINVAL (-1429577717L) +#define PROF_READ_ONLY (-1429577716L) +#define PROF_SECTION_NOTOP (-1429577715L) +#define PROF_SECTION_SYNTAX (-1429577714L) +#define PROF_RELATION_SYNTAX (-1429577713L) +#define PROF_EXTRA_CBRACE (-1429577712L) +#define PROF_MISSING_OBRACE (-1429577711L) +#define PROF_MAGIC_PROFILE (-1429577710L) +#define PROF_MAGIC_SECTION (-1429577709L) +#define PROF_TOPSECTION_ITER_NOSUPP (-1429577708L) +#define PROF_INVALID_SECTION (-1429577707L) +#define PROF_END_OF_SECTIONS (-1429577706L) +#define PROF_BAD_NAMESET (-1429577705L) +#define PROF_NO_PROFILE (-1429577704L) +#define PROF_MAGIC_FILE (-1429577703L) +#define PROF_FAIL_OPEN (-1429577702L) +#define PROF_EXISTS (-1429577701L) +#define PROF_BAD_BOOLEAN (-1429577700L) +#define PROF_BAD_INTEGER (-1429577699L) +#define PROF_MAGIC_FILE_DATA (-1429577698L) +extern const struct error_table et_prof_error_table; +extern void initialize_prof_error_table(void); + +/* For compatibility with Heimdal */ +extern void initialize_prof_error_table_r(struct et_list **list); + +#define ERROR_TABLE_BASE_prof (-1429577728L) + +/* for compatibility with older versions... */ +#define init_prof_err_tbl initialize_prof_error_table +#define prof_err_base ERROR_TABLE_BASE_prof diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/profile.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/profile.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,1910 @@ +/* + * profile.c -- A simple configuration file parsing "library in a file" + * + * The profile library was originally written by Theodore Ts'o in 1995 + * for use in the MIT Kerberos v5 library. It has been + * modified/enhanced/bug-fixed over time by other members of the MIT + * Kerberos team. This version was originally taken from the Kerberos + * v5 distribution, version 1.4.2, and radically simplified for use in + * e2fsprogs. (Support for locking for multi-threaded operations, + * being able to modify and update the configuration file + * programmatically, and Mac/Windows portability have been removed. + * It has been folded into a single C source file to make it easier to + * fold into an application program.) + * + * Copyright (C) 2005, 2006 by Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + * + * Copyright (C) 1985-2005 by the Massachusetts Institute of Technology. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original MIT software. + * M.I.T. makes no representations about the suitability of this software + * for any purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#include "config.h" +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_PWD_H +#include +#endif + +#include +#include "profile.h" +#include "prof_err.h" + +#undef STAT_ONCE_PER_SECOND +#undef HAVE_STAT + +/* + * prof_int.h + */ + +typedef long prf_magic_t; + +/* + * This is the structure which stores the profile information for a + * particular configuration file. + */ +struct _prf_file_t { + prf_magic_t magic; + char *filespec; +#ifdef STAT_ONCE_PER_SECOND + time_t last_stat; +#endif + time_t timestamp; /* time tree was last updated from file */ + int flags; /* r/w, dirty */ + int upd_serial; /* incremented when data changes */ + struct profile_node *root; + struct _prf_file_t *next; +}; + +typedef struct _prf_file_t *prf_file_t; + +/* + * The profile flags + */ +#define PROFILE_FILE_RW 0x0001 +#define PROFILE_FILE_DIRTY 0x0002 +#define PROFILE_FILE_NO_RELOAD 0x0004 + +/* + * This structure defines the high-level, user visible profile_t + * object, which is used as a handle by users who need to query some + * configuration file(s) + */ +struct _profile_t { + prf_magic_t magic; + prf_file_t first_file; +}; + +/* + * Used by the profile iterator in prof_get.c + */ +#define PROFILE_ITER_LIST_SECTION 0x0001 +#define PROFILE_ITER_SECTIONS_ONLY 0x0002 +#define PROFILE_ITER_RELATIONS_ONLY 0x0004 + +#define PROFILE_ITER_FINAL_SEEN 0x0100 + +/* + * Check if a filespec is last in a list (NULL on UNIX, invalid FSSpec on MacOS + */ + +#define PROFILE_LAST_FILESPEC(x) (((x) == NULL) || ((x)[0] == '\0')) + +struct profile_node { + errcode_t magic; + char *name; + char *value; + int group_level; + unsigned int final:1; /* Indicate don't search next file */ + unsigned int deleted:1; + struct profile_node *first_child; + struct profile_node *parent; + struct profile_node *next, *prev; +}; + +#define CHECK_MAGIC(node) \ + if ((node)->magic != PROF_MAGIC_NODE) \ + return PROF_MAGIC_NODE; + +/* profile parser declarations */ +struct parse_state { + int state; + int group_level; + int line_num; + struct profile_node *root_section; + struct profile_node *current_section; +}; + +static const char *default_filename = ""; + +static profile_syntax_err_cb_t syntax_err_cb; + +static errcode_t parse_line(char *line, struct parse_state *state); + +#ifdef DEBUG_PROGRAM +static errcode_t profile_write_tree_file + (struct profile_node *root, FILE *dstfile); + +static errcode_t profile_write_tree_to_buffer + (struct profile_node *root, char **buf); +#endif + + +static void profile_free_node + (struct profile_node *relation); + +static errcode_t profile_create_node + (const char *name, const char *value, + struct profile_node **ret_node); + +#ifdef DEBUG_PROGRAM +static errcode_t profile_verify_node + (struct profile_node *node); +#endif + +static errcode_t profile_add_node + (struct profile_node *section, + const char *name, const char *value, + struct profile_node **ret_node); + +static errcode_t profile_find_node + (struct profile_node *section, + const char *name, const char *value, + int section_flag, void **state, + struct profile_node **node); + +static errcode_t profile_node_iterator + (void **iter_p, struct profile_node **ret_node, + char **ret_name, char **ret_value); + +static errcode_t profile_open_file + (const char * file, prf_file_t *ret_prof); + +static errcode_t profile_update_file + (prf_file_t prf); + +static void profile_free_file + (prf_file_t profile); + +static errcode_t profile_get_value(profile_t profile, const char *name, + const char *subname, const char *subsubname, + const char **ret_value); + + +/* + * prof_init.c --- routines that manipulate the user-visible profile_t + * object. + */ + +static int compstr(const void *m1, const void *m2) +{ + const char *s1 = *((const char * const *) m1); + const char *s2 = *((const char * const *) m2); + + return strcmp(s1, s2); +} + +static void free_list(char **list) +{ + char **cp; + + if (list == 0) + return; + + for (cp = list; *cp; cp++) + free(*cp); + free(list); +} + +static errcode_t get_dirlist(const char *dirname, char***ret_array) +{ + DIR *dir; + struct dirent *de; + struct stat st; + errcode_t retval; + char *fn, *cp; + char **array = 0, **new_array; + int max = 0, num = 0; + + dir = opendir(dirname); + if (!dir) + return errno; + + while ((de = readdir(dir)) != NULL) { + for (cp = de->d_name; *cp; cp++) { + if (!isalnum(*cp) && + (*cp != '-') && + (*cp != '_')) + break; + } + if (*cp) + continue; + fn = malloc(strlen(dirname) + strlen(de->d_name) + 2); + if (!fn) { + retval = ENOMEM; + goto errout; + } + sprintf(fn, "%s/%s", dirname, de->d_name); + if ((stat(fn, &st) < 0) || !S_ISREG(st.st_mode)) { + free(fn); + continue; + } + if (num >= max) { + max += 10; + new_array = realloc(array, sizeof(char *) * (max+1)); + if (!new_array) { + retval = ENOMEM; + free(fn); + goto errout; + } + array = new_array; + } + array[num++] = fn; + } + if (array) { + qsort(array, num, sizeof(char *), compstr); + array[num++] = 0; + } + *ret_array = array; + closedir(dir); + return 0; +errout: + if (array) + array[num] = 0; + closedir(dir); + free_list(array); + return retval; +} + +errcode_t +profile_init(const char * const *files, profile_t *ret_profile) +{ + const char * const *fs; + profile_t profile; + prf_file_t new_file, *last; + errcode_t retval = 0; + char **cpp, *cp, **array = 0; + + profile = malloc(sizeof(struct _profile_t)); + if (!profile) + return ENOMEM; + memset(profile, 0, sizeof(struct _profile_t)); + profile->magic = PROF_MAGIC_PROFILE; + last = &profile->first_file; + + /* if the filenames list is not specified return an empty profile */ + if ( files ) { + for (fs = files; !PROFILE_LAST_FILESPEC(*fs); fs++) { + if (array) + free_list(array); + array = NULL; + retval = get_dirlist(*fs, &array); + if (retval == 0) { + if (!array) + continue; + for (cpp = array; (cp = *cpp); cpp++) { + retval = profile_open_file(cp, &new_file); + if (retval == EACCES) + continue; + if (retval) + goto errout; + *last = new_file; + last = &new_file->next; + } + } else if ((retval != ENOTDIR) && + strcmp(*fs, default_filename)) + goto errout; + + retval = profile_open_file(*fs, &new_file); + /* if this file is missing, skip to the next */ + if (retval == ENOENT || retval == EACCES) { + continue; + } + if (retval) + goto errout; + *last = new_file; + last = &new_file->next; + } + /* + * If all the files were not found, return the appropriate error. + */ + if (!profile->first_file) { + retval = ENOENT; + goto errout; + } + } + + free_list(array); + *ret_profile = profile; + return 0; +errout: + free_list(array); + profile_release(profile); + return retval; +} + +void +profile_release(profile_t profile) +{ + prf_file_t p, next; + + if (!profile || profile->magic != PROF_MAGIC_PROFILE) + return; + + for (p = profile->first_file; p; p = next) { + next = p->next; + profile_free_file(p); + } + profile->magic = 0; + free(profile); +} + +/* + * This function sets the value of the pseudo file "". If + * the file "" had previously been passed to profile_init(), + * then def_string parameter will be parsed and used as the profile + * information for the "" file. + */ +errcode_t profile_set_default(profile_t profile, const char *def_string) +{ + struct parse_state state; + prf_file_t prf; + errcode_t retval; + const char *in; + char *line, *p, *end; + int line_size, len; + + if (!def_string || !profile || profile->magic != PROF_MAGIC_PROFILE) + return PROF_MAGIC_PROFILE; + + for (prf = profile->first_file; prf; prf = prf->next) { + if (strcmp(prf->filespec, default_filename) == 0) + break; + } + if (!prf) + return 0; + + if (prf->root) { + profile_free_node(prf->root); + prf->root = 0; + } + + memset(&state, 0, sizeof(struct parse_state)); + retval = profile_create_node("(root)", 0, &state.root_section); + if (retval) + return retval; + + line = 0; + line_size = 0; + in = def_string; + while (*in) { + end = strchr(in, '\n'); + len = end ? (end - in) : (int) strlen(in); + if (len >= line_size) { + line_size = len+1; + p = realloc(line, line_size); + if (!p) { + retval = ENOMEM; + goto errout; + } + line = p; + } + memcpy(line, in, len); + line[len] = 0; + retval = parse_line(line, &state); + if (retval) { + errout: + if (syntax_err_cb) + (syntax_err_cb)(prf->filespec, retval, + state.line_num); + free(line); + if (prf->root) + profile_free_node(prf->root); + return retval; + } + if (!end) + break; + in = end+1; + } + prf->root = state.root_section; + free(line); + + return 0; +} + +/* + * prof_file.c ---- routines that manipulate an individual profile file. + */ + +errcode_t profile_open_file(const char * filespec, + prf_file_t *ret_prof) +{ + prf_file_t prf; + errcode_t retval; + char *home_env = 0; + unsigned int len; + char *expanded_filename; + + prf = malloc(sizeof(struct _prf_file_t)); + if (!prf) + return ENOMEM; + memset(prf, 0, sizeof(struct _prf_file_t)); + prf->magic = PROF_MAGIC_FILE; + + len = strlen(filespec)+1; + if (filespec[0] == '~' && filespec[1] == '/') { + home_env = getenv("HOME"); +#ifdef HAVE_PWD_H + if (home_env == NULL) { +#ifdef HAVE_GETWUID_R + struct passwd *pw, pwx; + uid_t uid; + char pwbuf[BUFSIZ]; + + uid = getuid(); + if (!getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) + && pw != NULL && pw->pw_dir[0] != 0) + home_env = pw->pw_dir; +#else + struct passwd *pw; + + pw = getpwuid(getuid()); + home_env = pw->pw_dir; +#endif + } +#endif + if (home_env) + len += strlen(home_env); + } + expanded_filename = malloc(len); + if (expanded_filename == 0) { + profile_free_file(prf); + return errno; + } + if (home_env) { + strcpy(expanded_filename, home_env); + strcat(expanded_filename, filespec+1); + } else + memcpy(expanded_filename, filespec, len); + + prf->filespec = expanded_filename; + + if (strcmp(prf->filespec, default_filename) != 0) { + retval = profile_update_file(prf); + if (retval) { + profile_free_file(prf); + return retval; + } + } + + *ret_prof = prf; + return 0; +} + +errcode_t profile_update_file(prf_file_t prf) +{ + errcode_t retval; +#ifdef HAVE_STAT + struct stat st; +#ifdef STAT_ONCE_PER_SECOND + time_t now; +#endif +#endif + FILE *f; + char buf[2048]; + struct parse_state state; + + if (prf->flags & PROFILE_FILE_NO_RELOAD) + return 0; + +#ifdef HAVE_STAT +#ifdef STAT_ONCE_PER_SECOND + now = time(0); + if (now == prf->last_stat && prf->root != NULL) { + return 0; + } +#endif + if (stat(prf->filespec, &st)) { + retval = errno; + return retval; + } +#ifdef STAT_ONCE_PER_SECOND + prf->last_stat = now; +#endif + if (st.st_mtime == prf->timestamp && prf->root != NULL) { + return 0; + } + if (prf->root) { + profile_free_node(prf->root); + prf->root = 0; + } +#else + /* + * If we don't have the stat() call, assume that our in-core + * memory image is correct. That is, we won't reread the + * profile file if it changes. + */ + if (prf->root) { + return 0; + } +#endif + memset(&state, 0, sizeof(struct parse_state)); + retval = profile_create_node("(root)", 0, &state.root_section); + if (retval) + return retval; + errno = 0; + f = fopen(prf->filespec, "r"); + if (f == NULL) { + retval = errno; + if (retval == 0) + retval = ENOENT; + return retval; + } + prf->upd_serial++; + while (!feof(f)) { + if (fgets(buf, sizeof(buf), f) == NULL) + break; + retval = parse_line(buf, &state); + if (retval) { + if (syntax_err_cb) + (syntax_err_cb)(prf->filespec, retval, + state.line_num); + fclose(f); + return retval; + } + } + prf->root = state.root_section; + + fclose(f); + +#ifdef HAVE_STAT + prf->timestamp = st.st_mtime; +#endif + return 0; +} + +void profile_free_file(prf_file_t prf) +{ + if (prf->root) + profile_free_node(prf->root); + free(prf->filespec); + free(prf); +} + +/* Begin the profile parser */ + +profile_syntax_err_cb_t profile_set_syntax_err_cb(profile_syntax_err_cb_t hook) +{ + profile_syntax_err_cb_t old; + + old = syntax_err_cb; + syntax_err_cb = hook; + return(old); +} + +#define STATE_INIT_COMMENT 0 +#define STATE_STD_LINE 1 +#define STATE_GET_OBRACE 2 + +static char *skip_over_blanks(char *cp) +{ + while (*cp && isspace((int) (*cp))) + cp++; + return cp; +} + +static int end_or_comment(char ch) +{ + return (ch == 0 || ch == '#' || ch == ';'); +} + +static char *skip_over_nonblanks(char *cp) +{ + while (!end_or_comment(*cp) && !isspace(*cp)) + cp++; + return cp; +} + +static void strip_line(char *line) +{ + char *p = line + strlen(line); + while (p > line && (p[-1] == '\n' || p[-1] == '\r')) + *p-- = 0; +} + +static void parse_quoted_string(char *str) +{ + char *to, *from; + + to = from = str; + + for (to = from = str; *from && *from != '"'; to++, from++) { + if (*from == '\\') { + from++; + switch (*from) { + case 'n': + *to = '\n'; + break; + case 't': + *to = '\t'; + break; + case 'b': + *to = '\b'; + break; + default: + *to = *from; + } + continue; + } + *to = *from; + } + *to = '\0'; +} + +static errcode_t parse_line(char *line, struct parse_state *state) +{ + char *cp, ch, *tag, *value; + char *p; + errcode_t retval; + struct profile_node *node; + int do_subsection = 0; + void *iter = 0; + + state->line_num++; + if (state->state == STATE_GET_OBRACE) { + cp = skip_over_blanks(line); + if (*cp != '{') + return PROF_MISSING_OBRACE; + state->state = STATE_STD_LINE; + return 0; + } + if (state->state == STATE_INIT_COMMENT) { + if (line[0] != '[') + return 0; + state->state = STATE_STD_LINE; + } + + if (*line == 0) + return 0; + strip_line(line); + cp = skip_over_blanks(line); + ch = *cp; + if (end_or_comment(ch)) + return 0; + if (ch == '[') { + if (state->group_level > 0) + return PROF_SECTION_NOTOP; + cp++; + cp = skip_over_blanks(cp); + p = strchr(cp, ']'); + if (p == NULL) + return PROF_SECTION_SYNTAX; + if (*cp == '"') { + cp++; + parse_quoted_string(cp); + } else { + *p-- = '\0'; + while (isspace(*p) && (p > cp)) + *p-- = '\0'; + if (*cp == 0) + return PROF_SECTION_SYNTAX; + } + retval = profile_find_node(state->root_section, cp, 0, 1, + &iter, &state->current_section); + if (retval == PROF_NO_SECTION) { + retval = profile_add_node(state->root_section, + cp, 0, + &state->current_section); + if (retval) + return retval; + } else if (retval) + return retval; + + /* + * Finish off the rest of the line. + */ + cp = p+1; + if (*cp == '*') { + state->current_section->final = 1; + cp++; + } + /* + * Spaces or comments after ']' should not be fatal + */ + cp = skip_over_blanks(cp); + if (!end_or_comment(*cp)) + return PROF_SECTION_SYNTAX; + return 0; + } + if (ch == '}') { + if (state->group_level == 0) + return PROF_EXTRA_CBRACE; + if (*(cp+1) == '*') + state->current_section->final = 1; + state->current_section = state->current_section->parent; + state->group_level--; + return 0; + } + /* + * Parse the relations + */ + tag = cp; + cp = strchr(cp, '='); + if (!cp) + return PROF_RELATION_SYNTAX; + if (cp == tag) + return PROF_RELATION_SYNTAX; + *cp = '\0'; + if (*tag == '"') { + tag++; + parse_quoted_string(tag); + } else { + /* Look for whitespace on left-hand side. */ + p = skip_over_nonblanks(tag); + if (*p) + *p++ = 0; + p = skip_over_blanks(p); + /* If we have more non-whitespace, it's an error. */ + if (*p) + return PROF_RELATION_SYNTAX; + } + + cp = skip_over_blanks(cp+1); + value = cp; + ch = value[0]; + if (ch == '"') { + value++; + parse_quoted_string(value); + } else if (end_or_comment(ch)) { + do_subsection++; + state->state = STATE_GET_OBRACE; + } else if (value[0] == '{') { + cp = skip_over_blanks(value+1); + ch = *cp; + if (end_or_comment(ch)) + do_subsection++; + else + return PROF_RELATION_SYNTAX; + } else { + cp = skip_over_nonblanks(value); + p = skip_over_blanks(cp); + ch = *p; + *cp = 0; + if (!end_or_comment(ch)) + return PROF_RELATION_SYNTAX; + } + if (do_subsection) { + p = strchr(tag, '*'); + if (p) + *p = '\0'; + retval = profile_add_node(state->current_section, + tag, 0, &state->current_section); + if (retval) + return retval; + if (p) + state->current_section->final = 1; + state->group_level++; + return 0; + } + p = strchr(tag, '*'); + if (p) + *p = '\0'; + profile_add_node(state->current_section, tag, value, &node); + if (p) + node->final = 1; + return 0; +} + +#ifdef DEBUG_PROGRAM +/* + * Return TRUE if the string begins or ends with whitespace + */ +static int need_double_quotes(char *str) +{ + if (!str || !*str) + return 0; + if (isspace((int) (*str)) ||isspace((int) (*(str + strlen(str) - 1)))) + return 1; + if (strchr(str, '\n') || strchr(str, '\t') || strchr(str, '\b') || + strchr(str, ' ') || strchr(str, '#') || strchr(str, ';')) + return 1; + return 0; +} + +/* + * Output a string with double quotes, doing appropriate backquoting + * of characters as necessary. + */ +static void output_quoted_string(char *str, void (*cb)(const char *,void *), + void *data) +{ + char ch; + char buf[2]; + + cb("\"", data); + if (!str) { + cb("\"", data); + return; + } + buf[1] = 0; + while ((ch = *str++)) { + switch (ch) { + case '\\': + cb("\\\\", data); + break; + case '\n': + cb("\\n", data); + break; + case '\t': + cb("\\t", data); + break; + case '\b': + cb("\\b", data); + break; + default: + /* This would be a lot faster if we scanned + forward for the next "interesting" + character. */ + buf[0] = ch; + cb(buf, data); + break; + } + } + cb("\"", data); +} + +#ifndef EOL +#define EOL "\n" +#endif + +/* Errors should be returned, not ignored! */ +static void dump_profile(struct profile_node *root, int level, + void (*cb)(const char *, void *), void *data) +{ + int i; + struct profile_node *p; + void *iter; + long retval; + + iter = 0; + do { + retval = profile_find_node(root, 0, 0, 0, &iter, &p); + if (retval) + break; + for (i=0; i < level; i++) + cb("\t", data); + if (need_double_quotes(p->name)) + output_quoted_string(p->name, cb, data); + else + cb(p->name, data); + cb(" = ", data); + if (need_double_quotes(p->value)) + output_quoted_string(p->value, cb, data); + else + cb(p->value, data); + cb(EOL, data); + } while (iter != 0); + + iter = 0; + do { + retval = profile_find_node(root, 0, 0, 1, &iter, &p); + if (retval) + break; + if (level == 0) { /* [xxx] */ + cb("[", data); + if (need_double_quotes(p->name)) + output_quoted_string(p->name, cb, data); + else + cb(p->name, data); + cb("]", data); + cb(p->final ? "*" : "", data); + cb(EOL, data); + dump_profile(p, level+1, cb, data); + cb(EOL, data); + } else { /* xxx = { ... } */ + for (i=0; i < level; i++) + cb("\t", data); + if (need_double_quotes(p->name)) + output_quoted_string(p->name, cb, data); + else + cb(p->name, data); + cb(" = {", data); + cb(EOL, data); + dump_profile(p, level+1, cb, data); + for (i=0; i < level; i++) + cb("\t", data); + cb("}", data); + cb(p->final ? "*" : "", data); + cb(EOL, data); + } + } while (iter != 0); +} + +static void dump_profile_to_file_cb(const char *str, void *data) +{ + fputs(str, data); +} + +errcode_t profile_write_tree_file(struct profile_node *root, FILE *dstfile) +{ + dump_profile(root, 0, dump_profile_to_file_cb, dstfile); + return 0; +} + +struct prof_buf { + char *base; + size_t cur, max; + int err; +}; + +static void add_data_to_buffer(struct prof_buf *b, const void *d, size_t len) +{ + if (b->err) + return; + if (b->max - b->cur < len) { + size_t newsize; + char *newptr; + + newsize = b->max + (b->max >> 1) + len + 1024; + newptr = realloc(b->base, newsize); + if (newptr == NULL) { + b->err = 1; + return; + } + b->base = newptr; + b->max = newsize; + } + memcpy(b->base + b->cur, d, len); + b->cur += len; /* ignore overflow */ +} + +static void dump_profile_to_buffer_cb(const char *str, void *data) +{ + add_data_to_buffer((struct prof_buf *)data, str, strlen(str)); +} + +errcode_t profile_write_tree_to_buffer(struct profile_node *root, + char **buf) +{ + struct prof_buf prof_buf = { 0, 0, 0, 0 }; + + dump_profile(root, 0, dump_profile_to_buffer_cb, &prof_buf); + if (prof_buf.err) { + *buf = NULL; + return ENOMEM; + } + add_data_to_buffer(&prof_buf, "", 1); /* append nul */ + if (prof_buf.max - prof_buf.cur > (prof_buf.max >> 3)) { + char *newptr = realloc(prof_buf.base, prof_buf.cur); + if (newptr) + prof_buf.base = newptr; + } + *buf = prof_buf.base; + return 0; +} +#endif + +/* + * prof_tree.c --- these routines maintain the parse tree of the + * config file. + * + * All of the details of how the tree is stored is abstracted away in + * this file; all of the other profile routines build, access, and + * modify the tree via the accessor functions found in this file. + * + * Each node may represent either a relation or a section header. + * + * A section header must have its value field set to 0, and may a one + * or more child nodes, pointed to by first_child. + * + * A relation has as its value a pointer to allocated memory + * containing a string. Its first_child pointer must be null. + * + */ + +/* + * Free a node, and any children + */ +void profile_free_node(struct profile_node *node) +{ + struct profile_node *child, *next; + + if (node->magic != PROF_MAGIC_NODE) + return; + + free(node->name); + free(node->value); + + for (child=node->first_child; child; child = next) { + next = child->next; + profile_free_node(child); + } + node->magic = 0; + + free(node); +} + +#ifndef HAVE_STRDUP +#undef strdup +#define strdup MYstrdup +static char *MYstrdup (const char *s) +{ + size_t sz = strlen(s) + 1; + char *p = malloc(sz); + if (p != 0) + memcpy(p, s, sz); + return p; +} +#endif + +/* + * Create a node + */ +errcode_t profile_create_node(const char *name, const char *value, + struct profile_node **ret_node) +{ + struct profile_node *new; + + new = malloc(sizeof(struct profile_node)); + if (!new) + return ENOMEM; + memset(new, 0, sizeof(struct profile_node)); + new->name = strdup(name); + if (new->name == 0) { + profile_free_node(new); + return ENOMEM; + } + if (value) { + new->value = strdup(value); + if (new->value == 0) { + profile_free_node(new); + return ENOMEM; + } + } + new->magic = PROF_MAGIC_NODE; + + *ret_node = new; + return 0; +} + +/* + * This function verifies that all of the representation invariants of + * the profile are true. If not, we have a programming bug somewhere, + * probably in this file. + */ +#ifdef DEBUG_PROGRAM +errcode_t profile_verify_node(struct profile_node *node) +{ + struct profile_node *p, *last; + errcode_t retval; + + CHECK_MAGIC(node); + + if (node->value && node->first_child) + return PROF_SECTION_WITH_VALUE; + + last = 0; + for (p = node->first_child; p; last = p, p = p->next) { + if (p->prev != last) + return PROF_BAD_LINK_LIST; + if (last && (last->next != p)) + return PROF_BAD_LINK_LIST; + if (node->group_level+1 != p->group_level) + return PROF_BAD_GROUP_LVL; + if (p->parent != node) + return PROF_BAD_PARENT_PTR; + retval = profile_verify_node(p); + if (retval) + return retval; + } + return 0; +} +#endif + +/* + * Add a node to a particular section + */ +errcode_t profile_add_node(struct profile_node *section, const char *name, + const char *value, struct profile_node **ret_node) +{ + errcode_t retval; + struct profile_node *p, *last, *new; + + CHECK_MAGIC(section); + + if (section->value) + return PROF_ADD_NOT_SECTION; + + /* + * Find the place to insert the new node. We look for the + * place *after* the last match of the node name, since + * order matters. + */ + for (p=section->first_child, last = 0; p; last = p, p = p->next) { + int cmp; + cmp = strcmp(p->name, name); + if (cmp > 0) + break; + } + retval = profile_create_node(name, value, &new); + if (retval) + return retval; + new->group_level = section->group_level+1; + new->deleted = 0; + new->parent = section; + new->prev = last; + new->next = p; + if (p) + p->prev = new; + if (last) + last->next = new; + else + section->first_child = new; + if (ret_node) + *ret_node = new; + return 0; +} + +/* + * Iterate through the section, returning the nodes which match + * the given name. If name is NULL, then interate through all the + * nodes in the section. If section_flag is non-zero, only return the + * section which matches the name; don't return relations. If value + * is non-NULL, then only return relations which match the requested + * value. (The value argument is ignored if section_flag is non-zero.) + * + * The first time this routine is called, the state pointer must be + * null. When this profile_find_node_relation() returns, if the state + * pointer is non-NULL, then this routine should be called again. + * (This won't happen if section_flag is non-zero, obviously.) + * + */ +errcode_t profile_find_node(struct profile_node *section, const char *name, + const char *value, int section_flag, void **state, + struct profile_node **node) +{ + struct profile_node *p; + + CHECK_MAGIC(section); + p = *state; + if (p) { + CHECK_MAGIC(p); + } else + p = section->first_child; + + for (; p; p = p->next) { + if (name && (strcmp(p->name, name))) + continue; + if (section_flag) { + if (p->value) + continue; + } else { + if (!p->value) + continue; + if (value && (strcmp(p->value, value))) + continue; + } + if (p->deleted) + continue; + /* A match! */ + if (node) + *node = p; + break; + } + if (p == 0) { + *state = 0; + return section_flag ? PROF_NO_SECTION : PROF_NO_RELATION; + } + /* + * OK, we've found one match; now let's try to find another + * one. This way, if we return a non-zero state pointer, + * there's guaranteed to be another match that's returned. + */ + for (p = p->next; p; p = p->next) { + if (name && (strcmp(p->name, name))) + continue; + if (section_flag) { + if (p->value) + continue; + } else { + if (!p->value) + continue; + if (value && (strcmp(p->value, value))) + continue; + } + /* A match! */ + break; + } + *state = p; + return 0; +} + +/* + * This is a general-purpose iterator for returning all nodes that + * match the specified name array. + */ +struct profile_iterator { + prf_magic_t magic; + profile_t profile; + int flags; + const char *const *names; + const char *name; + prf_file_t file; + int file_serial; + int done_idx; + struct profile_node *node; + int num; +}; + +errcode_t +profile_iterator_create(profile_t profile, const char *const *names, int flags, + void **ret_iter) +{ + struct profile_iterator *iter; + int done_idx = 0; + + if (profile == 0) + return PROF_NO_PROFILE; + if (profile->magic != PROF_MAGIC_PROFILE) + return PROF_MAGIC_PROFILE; + if (!names) + return PROF_BAD_NAMESET; + if (!(flags & PROFILE_ITER_LIST_SECTION)) { + if (!names[0]) + return PROF_BAD_NAMESET; + done_idx = 1; + } + + if ((iter = malloc(sizeof(struct profile_iterator))) == NULL) + return ENOMEM; + + iter->magic = PROF_MAGIC_ITERATOR; + iter->profile = profile; + iter->names = names; + iter->flags = flags; + iter->file = profile->first_file; + iter->done_idx = done_idx; + iter->node = 0; + iter->num = 0; + *ret_iter = iter; + return 0; +} + +void profile_iterator_free(void **iter_p) +{ + struct profile_iterator *iter; + + if (!iter_p) + return; + iter = *iter_p; + if (!iter || iter->magic != PROF_MAGIC_ITERATOR) + return; + free(iter); + *iter_p = 0; +} + +/* + * Note: the returned character strings in ret_name and ret_value + * points to the stored character string in the parse string. Before + * this string value is returned to a calling application + * (profile_node_iterator is not an exported interface), it should be + * strdup()'ed. + */ +errcode_t profile_node_iterator(void **iter_p, struct profile_node **ret_node, + char **ret_name, char **ret_value) +{ + struct profile_iterator *iter = *iter_p; + struct profile_node *section, *p; + const char *const *cpp; + errcode_t retval; + int skip_num = 0; + + if (!iter || iter->magic != PROF_MAGIC_ITERATOR) + return PROF_MAGIC_ITERATOR; + if (iter->file && iter->file->magic != PROF_MAGIC_FILE) + return PROF_MAGIC_FILE; + /* + * If the file has changed, then the node pointer is invalid, + * so we'll have search the file again looking for it. + */ + if (iter->node && (iter->file && + iter->file->upd_serial != iter->file_serial)) { + iter->flags &= ~PROFILE_ITER_FINAL_SEEN; + skip_num = iter->num; + iter->node = 0; + } + if (iter->node && iter->node->magic != PROF_MAGIC_NODE) { + return PROF_MAGIC_NODE; + } +get_new_file: + if (iter->node == 0) { + if (iter->file == NULL || + (iter->flags & PROFILE_ITER_FINAL_SEEN)) { + profile_iterator_free(iter_p); + if (ret_node) + *ret_node = 0; + if (ret_name) + *ret_name = 0; + if (ret_value) + *ret_value =0; + return 0; + } + if ((retval = profile_update_file(iter->file))) { + if (retval == ENOENT || retval == EACCES) { + /* XXX memory leak? */ + if (iter->file) + iter->file = iter->file->next; + skip_num = 0; + retval = 0; + goto get_new_file; + } else { + profile_iterator_free(iter_p); + return retval; + } + } + iter->file_serial = iter->file->upd_serial; + /* + * Find the section to list if we are a LIST_SECTION, + * or find the containing section if not. + */ + section = iter->file->root; + for (cpp = iter->names; cpp[iter->done_idx]; cpp++) { + for (p=section->first_child; p; p = p->next) { + if (!strcmp(p->name, *cpp) && !p->value) + break; + } + if (!p) { + section = 0; + break; + } + section = p; + if (p->final) + iter->flags |= PROFILE_ITER_FINAL_SEEN; + } + if (!section) { + if (iter->file) + iter->file = iter->file->next; + skip_num = 0; + goto get_new_file; + } + iter->name = *cpp; + iter->node = section->first_child; + } + /* + * OK, now we know iter->node is set up correctly. Let's do + * the search. + */ + for (p = iter->node; p; p = p->next) { + if (iter->name && strcmp(p->name, iter->name)) + continue; + if ((iter->flags & PROFILE_ITER_SECTIONS_ONLY) && + p->value) + continue; + if ((iter->flags & PROFILE_ITER_RELATIONS_ONLY) && + !p->value) + continue; + if (skip_num > 0) { + skip_num--; + continue; + } + if (p->deleted) + continue; + break; + } + iter->num++; + if (!p) { + if (iter->file) + iter->file = iter->file->next; + iter->node = 0; + skip_num = 0; + goto get_new_file; + } + if ((iter->node = p->next) == NULL) + if (iter->file) + iter->file = iter->file->next; + if (ret_node) + *ret_node = p; + if (ret_name) + *ret_name = p->name; + if (ret_value) + *ret_value = p->value; + return 0; +} + + +/* + * prof_get.c --- routines that expose the public interfaces for + * querying items from the profile. + * + */ + +/* + * This function only gets the first value from the file; it is a + * helper function for profile_get_string, profile_get_integer, etc. + */ +errcode_t profile_get_value(profile_t profile, const char *name, + const char *subname, const char *subsubname, + const char **ret_value) +{ + errcode_t retval; + void *state; + char *value; + const char *names[4]; + + names[0] = name; + names[1] = subname; + names[2] = subsubname; + names[3] = 0; + + if ((retval = profile_iterator_create(profile, names, + PROFILE_ITER_RELATIONS_ONLY, + &state))) + return retval; + + if ((retval = profile_node_iterator(&state, 0, 0, &value))) + goto cleanup; + + if (value) + *ret_value = value; + else + retval = PROF_NO_RELATION; + +cleanup: + profile_iterator_free(&state); + return retval; +} + +errcode_t +profile_get_string(profile_t profile, const char *name, const char *subname, + const char *subsubname, const char *def_val, + char **ret_string) +{ + const char *value; + errcode_t retval; + + if (profile) { + retval = profile_get_value(profile, name, subname, + subsubname, &value); + if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) + value = def_val; + else if (retval) + return retval; + } else + value = def_val; + + if (value) { + *ret_string = malloc(strlen(value)+1); + if (*ret_string == 0) + return ENOMEM; + strcpy(*ret_string, value); + } else + *ret_string = 0; + return 0; +} + +errcode_t +profile_get_integer(profile_t profile, const char *name, const char *subname, + const char *subsubname, int def_val, int *ret_int) +{ + const char *value; + errcode_t retval; + char *end_value; + long ret_long; + + *ret_int = def_val; + if (profile == 0) + return 0; + + retval = profile_get_value(profile, name, subname, subsubname, &value); + if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { + *ret_int = def_val; + return 0; + } else if (retval) + return retval; + + if (value[0] == 0) + /* Empty string is no good. */ + return PROF_BAD_INTEGER; + errno = 0; + ret_long = strtol(value, &end_value, 0); + + /* Overflow or underflow. */ + if ((ret_long == LONG_MIN || ret_long == LONG_MAX) && errno != 0) + return PROF_BAD_INTEGER; + /* Value outside "int" range. */ + if ((long) (int) ret_long != ret_long) + return PROF_BAD_INTEGER; + /* Garbage in string. */ + if (end_value != value + strlen (value)) + return PROF_BAD_INTEGER; + + + *ret_int = ret_long; + return 0; +} + +errcode_t +profile_get_uint(profile_t profile, const char *name, const char *subname, + const char *subsubname, unsigned int def_val, + unsigned int *ret_int) +{ + const char *value; + errcode_t retval; + char *end_value; + unsigned long ret_long; + + *ret_int = def_val; + if (profile == 0) + return 0; + + retval = profile_get_value(profile, name, subname, subsubname, &value); + if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { + *ret_int = def_val; + return 0; + } else if (retval) + return retval; + + if (value[0] == 0) + /* Empty string is no good. */ + return PROF_BAD_INTEGER; + errno = 0; + ret_long = strtoul(value, &end_value, 0); + + /* Overflow or underflow. */ + if ((ret_long == ULONG_MAX) && errno != 0) + return PROF_BAD_INTEGER; + /* Value outside "int" range. */ + if ((unsigned long) (unsigned int) ret_long != ret_long) + return PROF_BAD_INTEGER; + /* Garbage in string. */ + if (end_value != value + strlen (value)) + return PROF_BAD_INTEGER; + + *ret_int = ret_long; + return 0; +} + +errcode_t +profile_get_double(profile_t profile, const char *name, const char *subname, + const char *subsubname, double def_val, double *ret_double) +{ + const char *value; + errcode_t retval; + char *end_value; + double double_val; + + *ret_double = def_val; + if (profile == 0) + return 0; + + retval = profile_get_value(profile, name, subname, subsubname, &value); + if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { + *ret_double = def_val; + return 0; + } else if (retval) + return retval; + + if (value[0] == 0) + /* Empty string is no good. */ + return PROF_BAD_INTEGER; + errno = 0; + double_val = strtod(value, &end_value); + + /* Overflow or underflow. */ + if (errno != 0) + return PROF_BAD_INTEGER; + /* Garbage in string. */ + if (end_value != value + strlen(value)) + return PROF_BAD_INTEGER; + + *ret_double = double_val; + return 0; +} + +static const char *const conf_yes[] = { + "y", "yes", "true", "t", "1", "on", + 0, +}; + +static const char *const conf_no[] = { + "n", "no", "false", "nil", "0", "off", + 0, +}; + +static errcode_t +profile_parse_boolean(const char *s, int *ret_boolean) +{ + const char *const *p; + + if (ret_boolean == NULL) + return PROF_EINVAL; + + for(p=conf_yes; *p; p++) { + if (!strcasecmp(*p,s)) { + *ret_boolean = 1; + return 0; + } + } + + for(p=conf_no; *p; p++) { + if (!strcasecmp(*p,s)) { + *ret_boolean = 0; + return 0; + } + } + + return PROF_BAD_BOOLEAN; +} + +errcode_t +profile_get_boolean(profile_t profile, const char *name, const char *subname, + const char *subsubname, int def_val, int *ret_boolean) +{ + const char *value; + errcode_t retval; + + if (profile == 0) { + *ret_boolean = def_val; + return 0; + } + + retval = profile_get_value(profile, name, subname, subsubname, &value); + if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { + *ret_boolean = def_val; + return 0; + } else if (retval) + return retval; + + return profile_parse_boolean (value, ret_boolean); +} + +errcode_t +profile_iterator(void **iter_p, char **ret_name, char **ret_value) +{ + char *name, *value; + errcode_t retval; + + retval = profile_node_iterator(iter_p, 0, &name, &value); + if (retval) + return retval; + + if (ret_name) { + if (name) { + *ret_name = malloc(strlen(name)+1); + if (!*ret_name) + return ENOMEM; + strcpy(*ret_name, name); + } else + *ret_name = 0; + } + if (ret_value) { + if (value) { + *ret_value = malloc(strlen(value)+1); + if (!*ret_value) { + if (ret_name) { + free(*ret_name); + *ret_name = 0; + } + return ENOMEM; + } + strcpy(*ret_value, value); + } else + *ret_value = 0; + } + return 0; +} + +#ifdef DEBUG_PROGRAM + +/* + * test_profile.c --- testing program for the profile routine + */ + +#include "argv_parse.h" +#include "profile_helpers.h" + +const char *program_name = "test_profile"; + +#define PRINT_VALUE 1 +#define PRINT_VALUES 2 + +static void do_cmd(profile_t profile, char **argv) +{ + errcode_t retval; + const char **names, *value; + char **values, **cpp; + char *cmd; + int print_status; + + cmd = *(argv); + names = (const char **) argv + 1; + print_status = 0; + retval = 0; + if (cmd == 0) + return; + if (!strcmp(cmd, "query")) { + retval = profile_get_values(profile, names, &values); + print_status = PRINT_VALUES; + } else if (!strcmp(cmd, "query1")) { + const char *name = 0; + const char *subname = 0; + const char *subsubname = 0; + + name = names[0]; + if (name) + subname = names[1]; + if (subname) + subsubname = names[2]; + if (subsubname && names[3]) { + fprintf(stderr, + "Only 3 levels are allowed with query1\n"); + retval = EINVAL; + } else + retval = profile_get_value(profile, name, subname, + subsubname, &value); + print_status = PRINT_VALUE; + } else if (!strcmp(cmd, "list_sections")) { + retval = profile_get_subsection_names(profile, names, + &values); + print_status = PRINT_VALUES; + } else if (!strcmp(cmd, "list_relations")) { + retval = profile_get_relation_names(profile, names, + &values); + print_status = PRINT_VALUES; + } else if (!strcmp(cmd, "dump")) { + retval = profile_write_tree_file + (profile->first_file->root, stdout); +#if 0 + } else if (!strcmp(cmd, "clear")) { + retval = profile_clear_relation(profile, names); + } else if (!strcmp(cmd, "update")) { + retval = profile_update_relation(profile, names+2, + *names, *(names+1)); +#endif + } else if (!strcmp(cmd, "verify")) { + retval = profile_verify_node + (profile->first_file->root); +#if 0 + } else if (!strcmp(cmd, "rename_section")) { + retval = profile_rename_section(profile, names+1, *names); + } else if (!strcmp(cmd, "add")) { + value = *names; + if (strcmp(value, "NULL") == 0) + value = NULL; + retval = profile_add_relation(profile, names+1, value); + } else if (!strcmp(cmd, "flush")) { + retval = profile_flush(profile); +#endif + } else { + printf("Invalid command.\n"); + } + if (retval) { + com_err(cmd, retval, ""); + print_status = 0; + } + switch (print_status) { + case PRINT_VALUE: + printf("%s\n", value); + break; + case PRINT_VALUES: + for (cpp = values; *cpp; cpp++) + printf("%s\n", *cpp); + profile_free_list(values); + break; + } +} + +static void do_batchmode(profile_t profile) +{ + int argc, ret; + char **argv; + char buf[256]; + + while (!feof(stdin)) { + if (fgets(buf, sizeof(buf), stdin) == NULL) + break; + printf(">%s", buf); + ret = argv_parse(buf, &argc, &argv); + if (ret != 0) { + printf("Argv_parse returned %d!\n", ret); + continue; + } + do_cmd(profile, argv); + printf("\n"); + argv_free(argv); + } + profile_release(profile); + exit(0); + +} + +void syntax_err_report(const char *filename, long err, int line_num) +{ + fprintf(stderr, "Syntax error in %s, line number %d: %s\n", + filename, line_num, error_message(err)); + exit(1); +} + +const char *default_str = "[foo]\n\tbar=quux\n\tsub = {\n\t\twin = true\n}\n"; + +int main(int argc, char **argv) +{ + profile_t profile; + long retval; + char *cmd; + + if (argc < 2) { + fprintf(stderr, "Usage: %s filename [cmd argset]\n", program_name); + exit(1); + } + + initialize_prof_error_table(); + + profile_set_syntax_err_cb(syntax_err_report); + + retval = profile_init_path(argv[1], &profile); + if (retval) { + com_err(program_name, retval, "while initializing profile"); + exit(1); + } + retval = profile_set_default(profile, default_str); + if (retval) { + com_err(program_name, retval, "while setting default"); + exit(1); + } + + cmd = *(argv+2); + if (!cmd || !strcmp(cmd, "batch")) + do_batchmode(profile); + else + do_cmd(profile, argv+2); + profile_release(profile); + + return 0; +} + +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/profile.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/profile.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,107 @@ +/* + * profile.h + * + * Copyright (C) 2005 by Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + * + * Copyright (C) 1985-2005 by the Massachusetts Institute of Technology. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original MIT software. + * M.I.T. makes no representations about the suitability of this software + * for any purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef _PROFILE_H +#define _PROFILE_H + +typedef struct _profile_t *profile_t; + +typedef void (*profile_syntax_err_cb_t)(const char *file, long err, + int line_num); + +/* + * Used by the profile iterator in prof_get.c + */ +#define PROFILE_ITER_LIST_SECTION 0x0001 +#define PROFILE_ITER_SECTIONS_ONLY 0x0002 +#define PROFILE_ITER_RELATIONS_ONLY 0x0004 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +long profile_init + (const char * const *files, profile_t *ret_profile); + +void profile_release + (profile_t profile); + +long profile_set_default + (profile_t profile, const char *def_string); + +long profile_get_string + (profile_t profile, const char *name, const char *subname, + const char *subsubname, const char *def_val, + char **ret_string); +long profile_get_integer + (profile_t profile, const char *name, const char *subname, + const char *subsubname, int def_val, + int *ret_default); + +long profile_get_uint + (profile_t profile, const char *name, const char *subname, + const char *subsubname, unsigned int def_val, + unsigned int *ret_int); + +long profile_get_double + (profile_t profile, const char *name, const char *subname, + const char *subsubname, double def_val, + double *ret_float); + +long profile_get_boolean + (profile_t profile, const char *name, const char *subname, + const char *subsubname, int def_val, + int *ret_default); + +long profile_iterator_create + (profile_t profile, const char *const *names, + int flags, void **ret_iter); + +void profile_iterator_free + (void **iter_p); + +long profile_iterator + (void **iter_p, char **ret_name, char **ret_value); + +profile_syntax_err_cb_t profile_set_syntax_err_cb(profile_syntax_err_cb_t hook); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _KRB5_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/profile_helpers.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/profile_helpers.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,317 @@ +/* + * profile_helpers.c -- Helper functions for the profile library + * + * These functions are not part of the "core" profile library, and do + * not require access to the internal functions and data structures of + * the profile library. They are mainly convenience functions for + * programs that want to do something unusual such as obtaining the + * list of sections or relations, or accessing multiple values from a + * relation that is listed more than once. This functionality can all + * be done using the profile_iterator abstraction, but it is less + * convenient. + * + * Copyright (C) 2006 by Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include + +#include +#include "profile.h" +#include "profile_helpers.h" +#include "prof_err.h" + +/* + * These functions --- init_list(), end_list(), and add_to_list() are + * internal functions used to build up a null-terminated char ** list + * of strings to be returned by functions like profile_get_values. + * + * The profile_string_list structure is used for internal booking + * purposes to build up the list, which is returned in *ret_list by + * the end_list() function. + * + * The publicly exported interface for freeing char** list is + * profile_free_list(). + */ + +struct profile_string_list { + char **list; + int num; + int max; +}; + +/* + * Initialize the string list abstraction. + */ +static errcode_t init_list(struct profile_string_list *list) +{ + list->num = 0; + list->max = 10; + list->list = malloc(list->max * sizeof(char *)); + if (list->list == 0) + return ENOMEM; + list->list[0] = 0; + return 0; +} + +/* + * Free any memory left over in the string abstraction, returning the + * built up list in *ret_list if it is non-null. + */ +static void end_list(struct profile_string_list *list, char ***ret_list) +{ + char **cp; + + if (list == 0) + return; + + if (ret_list) { + *ret_list = list->list; + return; + } else { + for (cp = list->list; *cp; cp++) + free(*cp); + free(list->list); + } + list->num = list->max = 0; + list->list = 0; +} + +/* + * Add a string to the list. + */ +static errcode_t add_to_list(struct profile_string_list *list, char *str) +{ + char **newlist; + int newmax; + + if (list->num+1 >= list->max) { + newmax = list->max + 10; + newlist = realloc(list->list, newmax * sizeof(char *)); + if (newlist == 0) + return ENOMEM; + list->max = newmax; + list->list = newlist; + } + + list->list[list->num++] = str; + list->list[list->num] = 0; + return 0; +} + +/* + * Return TRUE if the string is already a member of the list. + */ +static int is_list_member(struct profile_string_list *list, const char *str) +{ + char **cpp; + + if (!list->list) + return 0; + + for (cpp = list->list; *cpp; cpp++) { + if (!strcmp(*cpp, str)) + return 1; + } + return 0; +} + +/* + * This function frees a null-terminated list as returned by + * profile_get_values. + */ +void profile_free_list(char **list) +{ + char **cp; + + if (list == 0) + return; + + for (cp = list; *cp; cp++) + free(*cp); + free(list); +} + +errcode_t +profile_get_values(profile_t profile, const char *const *names, + char ***ret_values) +{ + errcode_t retval; + void *state; + char *value; + struct profile_string_list values; + + if ((retval = profile_iterator_create(profile, names, + PROFILE_ITER_RELATIONS_ONLY, + &state))) + return retval; + + if ((retval = init_list(&values))) + goto cleanup_iterator; + + do { + if ((retval = profile_iterator(&state, 0, &value))) + goto cleanup; + if (value) + add_to_list(&values, value); + } while (state); + + if (values.num == 0) { + retval = PROF_NO_RELATION; + goto cleanup; + } + + end_list(&values, ret_values); + return 0; + +cleanup: + end_list(&values, 0); +cleanup_iterator: + profile_iterator_free(&state); + return retval; +} + +/* + * This function will return the list of the names of subsections in the + * under the specified section name. + */ +errcode_t +profile_get_subsection_names(profile_t profile, const char **names, + char ***ret_names) +{ + errcode_t retval; + void *state; + char *name; + struct profile_string_list values; + + if ((retval = profile_iterator_create(profile, names, + PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY, + &state))) + return retval; + + if ((retval = init_list(&values))) + goto cleanup_iterator; + + do { + if ((retval = profile_iterator(&state, &name, 0))) + goto cleanup; + if (name) + add_to_list(&values, name); + } while (state); + + end_list(&values, ret_names); + return 0; + +cleanup: + end_list(&values, 0); +cleanup_iterator: + profile_iterator_free(&state); + return retval; +} + +/* + * This function will return the list of the names of relations in the + * under the specified section name. + */ +errcode_t +profile_get_relation_names(profile_t profile, const char **names, + char ***ret_names) +{ + errcode_t retval; + void *state; + char *name; + struct profile_string_list values; + + if ((retval = profile_iterator_create(profile, names, + PROFILE_ITER_LIST_SECTION | PROFILE_ITER_RELATIONS_ONLY, + &state))) + return retval; + + if ((retval = init_list(&values))) + goto cleanup_iterator; + + do { + if ((retval = profile_iterator(&state, &name, 0))) + goto cleanup; + if (name) { + if (is_list_member(&values, name)) + free(name); + else + add_to_list(&values, name); + } + } while (state); + + end_list(&values, ret_names); + return 0; + +cleanup: + end_list(&values, 0); +cleanup_iterator: + profile_iterator_free(&state); + return retval; +} + + +void +profile_release_string(char *str) +{ + free(str); +} + +errcode_t +profile_init_path(const char * filepath, + profile_t *ret_profile) +{ + int n_entries, i; + unsigned int ent_len; + const char *s, *t; + char **filenames; + errcode_t retval; + + /* count the distinct filename components */ + for(s = filepath, n_entries = 1; *s; s++) { + if (*s == ':') + n_entries++; + } + + /* the array is NULL terminated */ + filenames = (char **) malloc((n_entries+1) * sizeof(char*)); + if (filenames == 0) + return ENOMEM; + + /* measure, copy, and skip each one */ + for(s = filepath, i=0; (t = strchr(s, ':')) || (t=s+strlen(s)); s=t+1, i++) { + ent_len = t-s; + filenames[i] = (char*) malloc(ent_len + 1); + if (filenames[i] == 0) { + /* if malloc fails, free the ones that worked */ + while(--i >= 0) free(filenames[i]); + free(filenames); + return ENOMEM; + } + strncpy(filenames[i], s, ent_len); + filenames[i][ent_len] = 0; + if (*t == 0) { + i++; + break; + } + } + /* cap the array */ + filenames[i] = 0; + + retval = profile_init((const char * const *) filenames, + ret_profile); + + /* count back down and free the entries */ + while(--i >= 0) free(filenames[i]); + free(filenames); + + return retval; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/profile_helpers.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/profile_helpers.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,28 @@ +/* + * profile_helpers.h -- Function prototypes for profile helper functions + * + * Copyright (C) 2006 by Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +long profile_get_values + (profile_t profile, const char *const *names, char ***ret_values); + +void profile_free_list + (char **list); + +long profile_get_relation_names + (profile_t profile, const char **names, char ***ret_names); + +long profile_get_subsection_names + (profile_t profile, const char **names, char ***ret_names); + +void profile_release_string (char *str); + +long profile_init_path + (const char * filelist, profile_t *ret_profile); + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/quotaio.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/quotaio.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,446 @@ +/** quotaio.c + * + * Generic IO operations on quotafiles + * Jan Kara - sponsored by SuSE CR + * Aditya Kali - Ported to e2fsprogs + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "quotaio.h" + +static const char * const extensions[MAXQUOTAS] = { + [USRQUOTA] = "user", + [GRPQUOTA] = "group", + [PRJQUOTA] = "project", +}; +static const char * const basenames[] = { + "", /* undefined */ + "quota", /* QFMT_VFS_OLD */ + "aquota", /* QFMT_VFS_V0 */ + "", /* QFMT_OCFS2 */ + "aquota" /* QFMT_VFS_V1 */ +}; + +/* Header in all newer quotafiles */ +struct disk_dqheader { + __le32 dqh_magic; + __le32 dqh_version; +} __attribute__ ((packed)); + +/** + * Convert type of quota to written representation + */ +const char *quota_type2name(enum quota_type qtype) +{ + if (qtype >= MAXQUOTAS) + return "unknown"; + return extensions[qtype]; +} + +ext2_ino_t quota_type2inum(enum quota_type qtype, + struct ext2_super_block *sb) +{ + switch (qtype) { + case USRQUOTA: + return EXT4_USR_QUOTA_INO; + case GRPQUOTA: + return EXT4_GRP_QUOTA_INO; + case PRJQUOTA: + return sb->s_prj_quota_inum; + default: + return 0; + } + return 0; +} + +/** + * Creates a quota file name for given type and format. + */ +const char *quota_get_qf_name(enum quota_type type, int fmt, char *buf) +{ + if (!buf) + return NULL; + snprintf(buf, QUOTA_NAME_LEN, "%s.%s", + basenames[fmt], extensions[type]); + + return buf; +} + +/* + * Set grace time if needed + */ +void update_grace_times(struct dquot *q) +{ + time_t now; + + time(&now); + if (q->dq_dqb.dqb_bsoftlimit && toqb(q->dq_dqb.dqb_curspace) > + q->dq_dqb.dqb_bsoftlimit) { + if (!q->dq_dqb.dqb_btime) + q->dq_dqb.dqb_btime = + now + q->dq_h->qh_info.dqi_bgrace; + } else { + q->dq_dqb.dqb_btime = 0; + } + + if (q->dq_dqb.dqb_isoftlimit && q->dq_dqb.dqb_curinodes > + q->dq_dqb.dqb_isoftlimit) { + if (!q->dq_dqb.dqb_itime) + q->dq_dqb.dqb_itime = + now + q->dq_h->qh_info.dqi_igrace; + } else { + q->dq_dqb.dqb_itime = 0; + } +} + +static int compute_num_blocks_proc(ext2_filsys fs EXT2FS_ATTR((unused)), + blk64_t *blocknr EXT2FS_ATTR((unused)), + e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), + blk64_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *private) +{ + blk64_t *num_blocks = private; + + *num_blocks += 1; + return 0; +} + +errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_inode inode; + errcode_t err; + enum quota_type qtype; + + if ((err = ext2fs_read_inode(fs, ino, &inode))) + return err; + + for (qtype = 0; qtype < MAXQUOTAS; qtype++) + if (ino == quota_type2inum(qtype, fs->super)) + break; + + if (qtype != MAXQUOTAS) { + inode.i_dtime = fs->now ? fs->now : time(0); + if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) + return 0; + err = ext2fs_punch(fs, ino, &inode, NULL, 0, ~0ULL); + if (err) + return err; + fs->flags &= ~EXT2_FLAG_SUPER_ONLY; + memset(&inode, 0, sizeof(struct ext2_inode)); + } else { + inode.i_flags &= ~EXT2_IMMUTABLE_FL; + } + err = ext2fs_write_inode(fs, ino, &inode); + return err; +} + +static ext2_off64_t compute_inode_size(ext2_filsys fs, ext2_ino_t ino) +{ + blk64_t num_blocks = 0; + + ext2fs_block_iterate3(fs, ino, + BLOCK_FLAG_READ_ONLY, + NULL, + compute_num_blocks_proc, + &num_blocks); + return num_blocks * fs->blocksize; +} + +/* Functions to read/write quota file. */ +static unsigned int quota_write_nomount(struct quota_file *qf, + ext2_loff_t offset, + void *buf, unsigned int size) +{ + ext2_file_t e2_file = qf->e2_file; + unsigned int bytes_written = 0; + errcode_t err; + + err = ext2fs_file_llseek(e2_file, offset, EXT2_SEEK_SET, NULL); + if (err) { + log_err("ext2fs_file_llseek failed: %ld", err); + return 0; + } + + err = ext2fs_file_write(e2_file, buf, size, &bytes_written); + if (err) { + log_err("ext2fs_file_write failed: %ld", err); + return 0; + } + + /* Correct inode.i_size is set in end_io. */ + return bytes_written; +} + +static unsigned int quota_read_nomount(struct quota_file *qf, + ext2_loff_t offset, + void *buf, unsigned int size) +{ + ext2_file_t e2_file = qf->e2_file; + unsigned int bytes_read = 0; + errcode_t err; + + err = ext2fs_file_llseek(e2_file, offset, EXT2_SEEK_SET, NULL); + if (err) { + log_err("ext2fs_file_llseek failed: %ld", err); + return 0; + } + + err = ext2fs_file_read(e2_file, buf, size, &bytes_read); + if (err) { + log_err("ext2fs_file_read failed: %ld", err); + return 0; + } + + return bytes_read; +} + +/* + * Detect quota format and initialize quota IO + */ +errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h, + ext2_ino_t qf_ino, enum quota_type qtype, + int fmt, int flags) +{ + ext2_filsys fs = qctx->fs; + ext2_file_t e2_file; + errcode_t err; + int allocated_handle = 0; + + if (qtype >= MAXQUOTAS) + return EINVAL; + + if (fmt == -1) + fmt = QFMT_VFS_V1; + + err = ext2fs_read_bitmaps(fs); + if (err) + return err; + + if (qf_ino == 0) + qf_ino = *quota_sb_inump(fs->super, qtype); + + log_debug("Opening quota ino=%u, type=%d", qf_ino, qtype); + err = ext2fs_file_open(fs, qf_ino, flags, &e2_file); + if (err) { + log_err("ext2fs_file_open failed: %s", error_message(err)); + return err; + } + + if (!h) { + if (qctx->quota_file[qtype]) { + h = qctx->quota_file[qtype]; + if (((flags & EXT2_FILE_WRITE) == 0) || + (h->qh_file_flags & EXT2_FILE_WRITE)) { + ext2fs_file_close(e2_file); + return 0; + } + (void) quota_file_close(qctx, h); + } + err = ext2fs_get_mem(sizeof(struct quota_handle), &h); + if (err) { + log_err("Unable to allocate quota handle"); + ext2fs_file_close(e2_file); + return err; + } + allocated_handle = 1; + } + + h->qh_qf.e2_file = e2_file; + h->qh_qf.fs = fs; + h->qh_qf.ino = qf_ino; + h->e2fs_write = quota_write_nomount; + h->e2fs_read = quota_read_nomount; + h->qh_file_flags = flags; + h->qh_io_flags = 0; + h->qh_type = qtype; + h->qh_fmt = fmt; + memset(&h->qh_info, 0, sizeof(h->qh_info)); + h->qh_ops = "afile_ops_2; + + if (h->qh_ops->check_file && + (h->qh_ops->check_file(h, qtype, fmt) == 0)) { + log_err("qh_ops->check_file failed"); + err = EIO; + goto errout; + } + + if (h->qh_ops->init_io && (h->qh_ops->init_io(h) < 0)) { + log_err("qh_ops->init_io failed"); + err = EIO; + goto errout; + } + if (allocated_handle) + qctx->quota_file[qtype] = h; + + return 0; +errout: + ext2fs_file_close(e2_file); + if (allocated_handle) + ext2fs_free_mem(&h); + return err; +} + +static errcode_t quota_inode_init_new(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_inode inode; + errcode_t err = 0; + + err = ext2fs_read_inode(fs, ino, &inode); + if (err) { + log_err("ex2fs_read_inode failed"); + return err; + } + + if (EXT2_I_SIZE(&inode)) { + err = quota_inode_truncate(fs, ino); + if (err) + return err; + } + + memset(&inode, 0, sizeof(struct ext2_inode)); + ext2fs_iblk_set(fs, &inode, 0); + inode.i_atime = inode.i_mtime = + inode.i_ctime = fs->now ? fs->now : time(0); + inode.i_links_count = 1; + inode.i_mode = LINUX_S_IFREG | 0600; + inode.i_flags |= EXT2_IMMUTABLE_FL; + if (ext2fs_has_feature_extents(fs->super)) + inode.i_flags |= EXT4_EXTENTS_FL; + + err = ext2fs_write_new_inode(fs, ino, &inode); + if (err) { + log_err("ext2fs_write_new_inode failed: %ld", err); + return err; + } + return err; +} + +/* + * Create new quotafile of specified format on given filesystem + */ +errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, + enum quota_type qtype, int fmt) +{ + ext2_file_t e2_file; + errcode_t err; + ext2_ino_t qf_inum = 0; + + if (fmt == -1) + fmt = QFMT_VFS_V1; + + h->qh_qf.fs = fs; + qf_inum = quota_type2inum(qtype, fs->super); + if (qf_inum == 0 && qtype == PRJQUOTA) { + err = ext2fs_new_inode(fs, EXT2_ROOT_INO, LINUX_S_IFREG | 0600, + 0, &qf_inum); + if (err) + return err; + ext2fs_inode_alloc_stats2(fs, qf_inum, +1, 0); + ext2fs_mark_ib_dirty(fs); + } else if (qf_inum == 0) { + return EXT2_ET_BAD_INODE_NUM; + } + + err = ext2fs_read_bitmaps(fs); + if (err) + goto out_err; + + err = quota_inode_init_new(fs, qf_inum); + if (err) { + log_err("init_new_quota_inode failed"); + goto out_err; + } + h->qh_qf.ino = qf_inum; + h->qh_file_flags = EXT2_FILE_WRITE | EXT2_FILE_CREATE; + h->e2fs_write = quota_write_nomount; + h->e2fs_read = quota_read_nomount; + + log_debug("Creating quota ino=%u, type=%d", qf_inum, qtype); + err = ext2fs_file_open(fs, qf_inum, h->qh_file_flags, &e2_file); + if (err) { + log_err("ext2fs_file_open failed: %ld", err); + goto out_err; + } + h->qh_qf.e2_file = e2_file; + + h->qh_io_flags = 0; + h->qh_type = qtype; + h->qh_fmt = fmt; + memset(&h->qh_info, 0, sizeof(h->qh_info)); + h->qh_ops = "afile_ops_2; + + if (h->qh_ops->new_io && (h->qh_ops->new_io(h) < 0)) { + log_err("qh_ops->new_io failed"); + err = EIO; + goto out_err1; + } + + return 0; + +out_err1: + ext2fs_file_close(e2_file); +out_err: + + if (qf_inum) + quota_inode_truncate(fs, qf_inum); + + return err; +} + +/* + * Close quotafile and release handle + */ +errcode_t quota_file_close(quota_ctx_t qctx, struct quota_handle *h) +{ + if (h->qh_io_flags & IOFL_INFODIRTY) { + if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0) + return EIO; + h->qh_io_flags &= ~IOFL_INFODIRTY; + } + + if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0) + return EIO; + if (h->qh_qf.e2_file) { + __u64 new_size, size; + + new_size = compute_inode_size(h->qh_qf.fs, h->qh_qf.ino); + ext2fs_file_flush(h->qh_qf.e2_file); + if (ext2fs_file_get_lsize(h->qh_qf.e2_file, &size)) + new_size = 0; + if (size != new_size) + ext2fs_file_set_size2(h->qh_qf.e2_file, new_size); + ext2fs_file_close(h->qh_qf.e2_file); + } + if (qctx->quota_file[h->qh_type] == h) + ext2fs_free_mem(&qctx->quota_file[h->qh_type]); + return 0; +} + +/* + * Create empty quota structure + */ +struct dquot *get_empty_dquot(void) +{ + struct dquot *dquot; + + if (ext2fs_get_memzero(sizeof(struct dquot), &dquot)) { + log_err("Failed to allocate dquot"); + return NULL; + } + + dquot->dq_id = -1; + return dquot; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/quotaio_tree.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/quotaio_tree.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,664 @@ +/* + * Implementation of new quotafile format + * + * Jan Kara - sponsored by SuSE CR + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "quotaio_tree.h" +#include "quotaio.h" + +typedef char *dqbuf_t; + +#define freedqbuf(buf) ext2fs_free_mem(&buf) + +static inline dqbuf_t getdqbuf(void) +{ + dqbuf_t buf; + if (ext2fs_get_memzero(QT_BLKSIZE, &buf)) { + log_err("Failed to allocate dqbuf"); + return NULL; + } + + return buf; +} + +/* Is given dquot empty? */ +int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk) +{ + unsigned int i; + + for (i = 0; i < info->dqi_entry_size; i++) + if (disk[i]) + return 0; + return 1; +} + +int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) +{ + return (QT_BLKSIZE - sizeof(struct qt_disk_dqdbheader)) / + info->dqi_entry_size; +} + +static int get_index(qid_t id, int depth) +{ + return (id >> ((QT_TREEDEPTH - depth - 1) * 8)) & 0xff; +} + +static inline void mark_quotafile_info_dirty(struct quota_handle *h) +{ + h->qh_io_flags |= IOFL_INFODIRTY; +} + +/* Read given block */ +static void read_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf) +{ + int err; + + err = h->e2fs_read(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf, + QT_BLKSIZE); + if (err < 0) + log_err("Cannot read block %u: %s", blk, strerror(errno)); + else if (err != QT_BLKSIZE) + memset(buf + err, 0, QT_BLKSIZE - err); +} + +/* Write block */ +static int write_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf) +{ + int err; + + err = h->e2fs_write(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf, + QT_BLKSIZE); + if (err < 0 && errno != ENOSPC) + log_err("Cannot write block (%u): %s", blk, strerror(errno)); + if (err != QT_BLKSIZE) + return -ENOSPC; + return 0; +} + +/* Get free block in file (either from free list or create new one) */ +static int get_free_dqblk(struct quota_handle *h) +{ + dqbuf_t buf = getdqbuf(); + struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + int blk; + + if (!buf) + return -ENOMEM; + + if (info->dqi_free_blk) { + blk = info->dqi_free_blk; + read_blk(h, blk, buf); + info->dqi_free_blk = ext2fs_le32_to_cpu(dh->dqdh_next_free); + } else { + memset(buf, 0, QT_BLKSIZE); + /* Assure block allocation... */ + if (write_blk(h, info->dqi_blocks, buf) < 0) { + freedqbuf(buf); + log_err("Cannot allocate new quota block " + "(out of disk space)."); + return -ENOSPC; + } + blk = info->dqi_blocks++; + } + mark_quotafile_info_dirty(h); + freedqbuf(buf); + return blk; +} + +/* Put given block to free list */ +static void put_free_dqblk(struct quota_handle *h, dqbuf_t buf, + unsigned int blk) +{ + struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + + dh->dqdh_next_free = ext2fs_cpu_to_le32(info->dqi_free_blk); + dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); + dh->dqdh_entries = ext2fs_cpu_to_le16(0); + info->dqi_free_blk = blk; + mark_quotafile_info_dirty(h); + write_blk(h, blk, buf); +} + +/* Remove given block from the list of blocks with free entries */ +static void remove_free_dqentry(struct quota_handle *h, dqbuf_t buf, + unsigned int blk) +{ + dqbuf_t tmpbuf = getdqbuf(); + struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; + unsigned int nextblk = ext2fs_le32_to_cpu(dh->dqdh_next_free), prevblk = + + ext2fs_le32_to_cpu(dh->dqdh_prev_free); + + if (!tmpbuf) + return; + + if (nextblk) { + read_blk(h, nextblk, tmpbuf); + ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = + dh->dqdh_prev_free; + write_blk(h, nextblk, tmpbuf); + } + if (prevblk) { + read_blk(h, prevblk, tmpbuf); + ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free = + dh->dqdh_next_free; + write_blk(h, prevblk, tmpbuf); + } else { + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = nextblk; + mark_quotafile_info_dirty(h); + } + freedqbuf(tmpbuf); + dh->dqdh_next_free = dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); + write_blk(h, blk, buf); /* No matter whether write succeeds + * block is out of list */ +} + +/* Insert given block to the beginning of list with free entries */ +static void insert_free_dqentry(struct quota_handle *h, dqbuf_t buf, + unsigned int blk) +{ + dqbuf_t tmpbuf = getdqbuf(); + struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + + if (!tmpbuf) + return; + + dh->dqdh_next_free = ext2fs_cpu_to_le32(info->dqi_free_entry); + dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); + write_blk(h, blk, buf); + if (info->dqi_free_entry) { + read_blk(h, info->dqi_free_entry, tmpbuf); + ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = + ext2fs_cpu_to_le32(blk); + write_blk(h, info->dqi_free_entry, tmpbuf); + } + freedqbuf(tmpbuf); + info->dqi_free_entry = blk; + mark_quotafile_info_dirty(h); +} + +/* Find space for dquot */ +static unsigned int find_free_dqentry(struct quota_handle *h, + struct dquot *dquot, int *err) +{ + int blk, i; + struct qt_disk_dqdbheader *dh; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + char *ddquot; + dqbuf_t buf; + + *err = 0; + buf = getdqbuf(); + if (!buf) { + *err = -ENOMEM; + return 0; + } + + dh = (struct qt_disk_dqdbheader *)buf; + if (info->dqi_free_entry) { + blk = info->dqi_free_entry; + read_blk(h, blk, buf); + } else { + blk = get_free_dqblk(h); + if (blk < 0) { + freedqbuf(buf); + *err = blk; + return 0; + } + memset(buf, 0, QT_BLKSIZE); + info->dqi_free_entry = blk; + mark_quotafile_info_dirty(h); + } + + /* Block will be full? */ + if (ext2fs_le16_to_cpu(dh->dqdh_entries) + 1 >= + qtree_dqstr_in_blk(info)) + remove_free_dqentry(h, buf, blk); + + dh->dqdh_entries = + ext2fs_cpu_to_le16(ext2fs_le16_to_cpu(dh->dqdh_entries) + 1); + /* Find free structure in block */ + ddquot = buf + sizeof(struct qt_disk_dqdbheader); + for (i = 0; + i < qtree_dqstr_in_blk(info) && !qtree_entry_unused(info, ddquot); + i++) + ddquot += info->dqi_entry_size; + + if (i == qtree_dqstr_in_blk(info)) + log_err("find_free_dqentry(): Data block full unexpectedly."); + + write_blk(h, blk, buf); + dquot->dq_dqb.u.v2_mdqb.dqb_off = + (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) + + i * info->dqi_entry_size; + freedqbuf(buf); + return blk; +} + +/* Insert reference to structure into the trie */ +static int do_insert_tree(struct quota_handle *h, struct dquot *dquot, + unsigned int * treeblk, int depth) +{ + dqbuf_t buf; + int newson = 0, newact = 0; + __le32 *ref; + unsigned int newblk; + int ret = 0; + + log_debug("inserting in tree: treeblk=%u, depth=%d", *treeblk, depth); + buf = getdqbuf(); + if (!buf) + return -ENOMEM; + + if (!*treeblk) { + ret = get_free_dqblk(h); + if (ret < 0) + goto out_buf; + *treeblk = ret; + memset(buf, 0, QT_BLKSIZE); + newact = 1; + } else { + read_blk(h, *treeblk, buf); + } + + ref = (__le32 *) buf; + newblk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); + if (!newblk) + newson = 1; + if (depth == QT_TREEDEPTH - 1) { + if (newblk) + log_err("Inserting already present quota entry " + "(block %u).", + ref[get_index(dquot->dq_id, depth)]); + newblk = find_free_dqentry(h, dquot, &ret); + } else { + ret = do_insert_tree(h, dquot, &newblk, depth + 1); + } + + if (newson && ret >= 0) { + ref[get_index(dquot->dq_id, depth)] = + ext2fs_cpu_to_le32(newblk); + write_blk(h, *treeblk, buf); + } else if (newact && ret < 0) { + put_free_dqblk(h, buf, *treeblk); + } + +out_buf: + freedqbuf(buf); + return ret; +} + +/* Wrapper for inserting quota structure into tree */ +static void dq_insert_tree(struct quota_handle *h, struct dquot *dquot) +{ + unsigned int tmp = QT_TREEOFF; + + if (do_insert_tree(h, dquot, &tmp, 0) < 0) + log_err("Cannot write quota (id %u): %s", + (unsigned int) dquot->dq_id, strerror(errno)); +} + +/* Write dquot to file */ +void qtree_write_dquot(struct dquot *dquot) +{ + errcode_t retval; + unsigned int ret; + char *ddquot; + struct quota_handle *h = dquot->dq_h; + struct qtree_mem_dqinfo *info = + &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; + log_debug("writing ddquot 1: off=%llu, info->dqi_entry_size=%u", + dquot->dq_dqb.u.v2_mdqb.dqb_off, + info->dqi_entry_size); + retval = ext2fs_get_mem(info->dqi_entry_size, &ddquot); + if (retval) { + errno = ENOMEM; + log_err("Quota write failed (id %u): %s", + (unsigned int)dquot->dq_id, strerror(errno)); + return; + } + memset(ddquot, 0, info->dqi_entry_size); + + if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) + dq_insert_tree(dquot->dq_h, dquot); + info->dqi_ops->mem2disk_dqblk(ddquot, dquot); + log_debug("writing ddquot 2: off=%llu, info->dqi_entry_size=%u", + dquot->dq_dqb.u.v2_mdqb.dqb_off, + info->dqi_entry_size); + ret = h->e2fs_write(&h->qh_qf, dquot->dq_dqb.u.v2_mdqb.dqb_off, ddquot, + info->dqi_entry_size); + + if (ret != info->dqi_entry_size) { + if (ret > 0) + errno = ENOSPC; + log_err("Quota write failed (id %u): %s", + (unsigned int)dquot->dq_id, strerror(errno)); + } + ext2fs_free_mem(&ddquot); +} + +/* Free dquot entry in data block */ +static void free_dqentry(struct quota_handle *h, struct dquot *dquot, + unsigned int blk) +{ + struct qt_disk_dqdbheader *dh; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + dqbuf_t buf = getdqbuf(); + + if (!buf) + return; + + if (dquot->dq_dqb.u.v2_mdqb.dqb_off >> QT_BLKSIZE_BITS != blk) + log_err("Quota structure has offset to other block (%u) " + "than it should (%u).", blk, + (unsigned int) (dquot->dq_dqb.u.v2_mdqb.dqb_off >> + QT_BLKSIZE_BITS)); + + read_blk(h, blk, buf); + dh = (struct qt_disk_dqdbheader *)buf; + dh->dqdh_entries = + ext2fs_cpu_to_le16(ext2fs_le16_to_cpu(dh->dqdh_entries) - 1); + + if (!ext2fs_le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ + remove_free_dqentry(h, buf, blk); + put_free_dqblk(h, buf, blk); + } else { + memset(buf + (dquot->dq_dqb.u.v2_mdqb.dqb_off & + ((1 << QT_BLKSIZE_BITS) - 1)), + 0, info->dqi_entry_size); + + /* First free entry? */ + if (ext2fs_le16_to_cpu(dh->dqdh_entries) == + qtree_dqstr_in_blk(info) - 1) + /* This will also write data block */ + insert_free_dqentry(h, buf, blk); + else + write_blk(h, blk, buf); + } + dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; + freedqbuf(buf); +} + +/* Remove reference to dquot from tree */ +static void remove_tree(struct quota_handle *h, struct dquot *dquot, + unsigned int * blk, int depth) +{ + dqbuf_t buf = getdqbuf(); + unsigned int newblk; + __le32 *ref = (__le32 *) buf; + + if (!buf) + return; + + read_blk(h, *blk, buf); + newblk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); + if (depth == QT_TREEDEPTH - 1) { + free_dqentry(h, dquot, newblk); + newblk = 0; + } else { + remove_tree(h, dquot, &newblk, depth + 1); + } + + if (!newblk) { + int i; + + ref[get_index(dquot->dq_id, depth)] = ext2fs_cpu_to_le32(0); + + /* Block got empty? */ + for (i = 0; i < QT_BLKSIZE && !buf[i]; i++); + + /* Don't put the root block into the free block list */ + if (i == QT_BLKSIZE && *blk != QT_TREEOFF) { + put_free_dqblk(h, buf, *blk); + *blk = 0; + } else { + write_blk(h, *blk, buf); + } + } + freedqbuf(buf); +} + +/* Delete dquot from tree */ +void qtree_delete_dquot(struct dquot *dquot) +{ + unsigned int tmp = QT_TREEOFF; + + if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) /* Even not allocated? */ + return; + remove_tree(dquot->dq_h, dquot, &tmp, 0); +} + +/* Find entry in block */ +static ext2_loff_t find_block_dqentry(struct quota_handle *h, + struct dquot *dquot, unsigned int blk) +{ + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + dqbuf_t buf = getdqbuf(); + int i; + char *ddquot = buf + sizeof(struct qt_disk_dqdbheader); + + if (!buf) + return -ENOMEM; + + read_blk(h, blk, buf); + for (i = 0; + i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot); + i++) + ddquot += info->dqi_entry_size; + + if (i == qtree_dqstr_in_blk(info)) + log_err("Quota for id %u referenced but not present.", + dquot->dq_id); + freedqbuf(buf); + return (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) + + i * info->dqi_entry_size; +} + +/* Find entry for given id in the tree */ +static ext2_loff_t find_tree_dqentry(struct quota_handle *h, + struct dquot *dquot, + unsigned int blk, int depth) +{ + dqbuf_t buf = getdqbuf(); + ext2_loff_t ret = 0; + __le32 *ref = (__le32 *) buf; + + if (!buf) + return -ENOMEM; + + read_blk(h, blk, buf); + ret = 0; + blk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); + if (!blk) /* No reference? */ + goto out_buf; + if (depth < QT_TREEDEPTH - 1) + ret = find_tree_dqentry(h, dquot, blk, depth + 1); + else + ret = find_block_dqentry(h, dquot, blk); +out_buf: + freedqbuf(buf); + return ret; +} + +/* Find entry for given id in the tree - wrapper function */ +static inline ext2_loff_t find_dqentry(struct quota_handle *h, + struct dquot *dquot) +{ + return find_tree_dqentry(h, dquot, QT_TREEOFF, 0); +} + +/* + * Read dquot from disk. + */ +struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id) +{ + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + ext2_loff_t offset; + unsigned int ret; + char *ddquot; + struct dquot *dquot = get_empty_dquot(); + + if (!dquot) + return NULL; + if (ext2fs_get_mem(info->dqi_entry_size, &ddquot)) { + ext2fs_free_mem(&dquot); + return NULL; + } + + dquot->dq_id = id; + dquot->dq_h = h; + dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; + memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk)); + + offset = find_dqentry(h, dquot); + if (offset > 0) { + dquot->dq_dqb.u.v2_mdqb.dqb_off = offset; + ret = h->e2fs_read(&h->qh_qf, offset, ddquot, + info->dqi_entry_size); + if (ret != info->dqi_entry_size) { + if (ret > 0) + errno = EIO; + log_err("Cannot read quota structure for id %u: %s", + dquot->dq_id, strerror(errno)); + } + info->dqi_ops->disk2mem_dqblk(dquot, ddquot); + } + ext2fs_free_mem(&ddquot); + return dquot; +} + +/* + * Scan all dquots in file and call callback on each + */ +#define set_bit(bmp, ind) ((bmp)[(ind) >> 3] |= (1 << ((ind) & 7))) +#define get_bit(bmp, ind) ((bmp)[(ind) >> 3] & (1 << ((ind) & 7))) + +static int report_block(struct dquot *dquot, unsigned int blk, char *bitmap, + int (*process_dquot) (struct dquot *, void *), + void *data) +{ + struct qtree_mem_dqinfo *info = + &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; + dqbuf_t buf = getdqbuf(); + struct qt_disk_dqdbheader *dh; + char *ddata; + int entries, i; + + if (!buf) + return 0; + + set_bit(bitmap, blk); + read_blk(dquot->dq_h, blk, buf); + dh = (struct qt_disk_dqdbheader *)buf; + ddata = buf + sizeof(struct qt_disk_dqdbheader); + entries = ext2fs_le16_to_cpu(dh->dqdh_entries); + for (i = 0; i < qtree_dqstr_in_blk(info); + i++, ddata += info->dqi_entry_size) + if (!qtree_entry_unused(info, ddata)) { + dquot->dq_dqb.u.v2_mdqb.dqb_off = + (blk << QT_BLKSIZE_BITS) + + sizeof(struct qt_disk_dqdbheader) + + i * info->dqi_entry_size; + info->dqi_ops->disk2mem_dqblk(dquot, ddata); + if (process_dquot(dquot, data) < 0) + break; + } + freedqbuf(buf); + return entries; +} + +static void check_reference(struct quota_handle *h, unsigned int blk) +{ + if (blk >= h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks) + log_err("Illegal reference (%u >= %u) in %s quota file. " + "Quota file is probably corrupted.\n" + "Please run e2fsck (8) to fix it.", + blk, + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks, + quota_type2name(h->qh_type)); +} + +static int report_tree(struct dquot *dquot, unsigned int blk, int depth, + char *bitmap, + int (*process_dquot) (struct dquot *, void *), + void *data) +{ + int entries = 0, i; + dqbuf_t buf = getdqbuf(); + __le32 *ref = (__le32 *) buf; + + if (!buf) + return 0; + + read_blk(dquot->dq_h, blk, buf); + if (depth == QT_TREEDEPTH - 1) { + for (i = 0; i < QT_BLKSIZE >> 2; i++) { + blk = ext2fs_le32_to_cpu(ref[i]); + check_reference(dquot->dq_h, blk); + if (blk && !get_bit(bitmap, blk)) + entries += report_block(dquot, blk, bitmap, + process_dquot, data); + } + } else { + for (i = 0; i < QT_BLKSIZE >> 2; i++) { + blk = ext2fs_le32_to_cpu(ref[i]); + if (blk) { + check_reference(dquot->dq_h, blk); + entries += report_tree(dquot, blk, depth + 1, + bitmap, process_dquot, + data); + } + } + } + freedqbuf(buf); + return entries; +} + +static unsigned int find_set_bits(char *bmp, int blocks) +{ + unsigned int used = 0; + int i; + + for (i = 0; i < blocks; i++) + if (get_bit(bmp, i)) + used++; + return used; +} + +int qtree_scan_dquots(struct quota_handle *h, + int (*process_dquot) (struct dquot *, void *), + void *data) +{ + char *bitmap; + struct v2_mem_dqinfo *v2info = &h->qh_info.u.v2_mdqi; + struct qtree_mem_dqinfo *info = &v2info->dqi_qtree; + struct dquot *dquot = get_empty_dquot(); + + if (!dquot) + return -1; + + dquot->dq_h = h; + if (ext2fs_get_memzero((info->dqi_blocks + 7) >> 3, &bitmap)) { + ext2fs_free_mem(&dquot); + return -1; + } + v2info->dqi_used_entries = report_tree(dquot, QT_TREEOFF, 0, bitmap, + process_dquot, data); + v2info->dqi_data_blocks = find_set_bits(bitmap, info->dqi_blocks); + ext2fs_free_mem(&bitmap); + ext2fs_free_mem(&dquot); + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/quotaio_tree.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/quotaio_tree.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,64 @@ +/* + * Definitions of structures for vfsv0 quota format + */ + +#ifndef _LINUX_QUOTA_TREE_H +#define _LINUX_QUOTA_TREE_H + +#include + +typedef __u32 qid_t; /* Type in which we store ids in memory */ + +#define QT_TREEOFF 1 /* Offset of tree in file in blocks */ +#define QT_TREEDEPTH 4 /* Depth of quota tree */ +#define QT_BLKSIZE_BITS 10 +#define QT_BLKSIZE (1 << QT_BLKSIZE_BITS) /* Size of block with quota + * structures */ + +/* + * Structure of header of block with quota structures. It is padded to 16 bytes + * so there will be space for exactly 21 quota-entries in a block + */ +struct qt_disk_dqdbheader { + __le32 dqdh_next_free; /* Number of next block with free + * entry */ + __le32 dqdh_prev_free; /* Number of previous block with free + * entry */ + __le16 dqdh_entries; /* Number of valid entries in block */ + __le16 dqdh_pad1; + __le32 dqdh_pad2; +} __attribute__ ((packed)); + +struct dquot; +struct quota_handle; + +/* Operations */ +struct qtree_fmt_operations { + /* Convert given entry from in memory format to disk one */ + void (*mem2disk_dqblk)(void *disk, struct dquot *dquot); + /* Convert given entry from disk format to in memory one */ + void (*disk2mem_dqblk)(struct dquot *dquot, void *disk); + /* Is this structure for given id? */ + int (*is_id)(void *disk, struct dquot *dquot); +}; + +/* In-memory copy of version specific information */ +struct qtree_mem_dqinfo { + unsigned int dqi_blocks; /* # of blocks in quota file */ + unsigned int dqi_free_blk; /* First block in list of free blocks */ + unsigned int dqi_free_entry; /* First block with free entry */ + unsigned int dqi_entry_size; /* Size of quota entry in quota file */ + struct qtree_fmt_operations *dqi_ops; /* Operations for entry + * manipulation */ +}; + +void qtree_write_dquot(struct dquot *dquot); +struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id); +void qtree_delete_dquot(struct dquot *dquot); +int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk); +int qtree_scan_dquots(struct quota_handle *h, + int (*process_dquot) (struct dquot *, void *), void *data); + +int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info); + +#endif /* _LINUX_QUOTAIO_TREE_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/quotaio_v2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/quotaio_v2.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,285 @@ +/* + * Implementation of new quotafile format + * + * Jan Kara - sponsored by SuSE CR + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "quotaio_v2.h" +#include "dqblk_v2.h" +#include "quotaio.h" +#include "quotaio_tree.h" + +static int v2_check_file(struct quota_handle *h, int type, int fmt); +static int v2_init_io(struct quota_handle *h); +static int v2_new_io(struct quota_handle *h); +static int v2_write_info(struct quota_handle *h); +static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id); +static int v2_commit_dquot(struct dquot *dquot); +static int v2_scan_dquots(struct quota_handle *h, + int (*process_dquot) (struct dquot *dquot, + void *data), + void *data); +static int v2_report(struct quota_handle *h, int verbose); + +struct quotafile_ops quotafile_ops_2 = { + .check_file = v2_check_file, + .init_io = v2_init_io, + .new_io = v2_new_io, + .write_info = v2_write_info, + .read_dquot = v2_read_dquot, + .commit_dquot = v2_commit_dquot, + .scan_dquots = v2_scan_dquots, + .report = v2_report, +}; + +/* + * Copy dquot from disk to memory + */ +static void v2r1_disk2memdqblk(struct dquot *dquot, void *dp) +{ + struct util_dqblk *m = &dquot->dq_dqb; + struct v2r1_disk_dqblk *d = dp, empty; + + dquot->dq_id = ext2fs_le32_to_cpu(d->dqb_id); + m->dqb_ihardlimit = ext2fs_le64_to_cpu(d->dqb_ihardlimit); + m->dqb_isoftlimit = ext2fs_le64_to_cpu(d->dqb_isoftlimit); + m->dqb_bhardlimit = ext2fs_le64_to_cpu(d->dqb_bhardlimit); + m->dqb_bsoftlimit = ext2fs_le64_to_cpu(d->dqb_bsoftlimit); + m->dqb_curinodes = ext2fs_le64_to_cpu(d->dqb_curinodes); + m->dqb_curspace = ext2fs_le64_to_cpu(d->dqb_curspace); + m->dqb_itime = ext2fs_le64_to_cpu(d->dqb_itime); + m->dqb_btime = ext2fs_le64_to_cpu(d->dqb_btime); + + memset(&empty, 0, sizeof(struct v2r1_disk_dqblk)); + empty.dqb_itime = ext2fs_cpu_to_le64(1); + if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk))) + m->dqb_itime = 0; +} + +/* + * Copy dquot from memory to disk + */ +static void v2r1_mem2diskdqblk(void *dp, struct dquot *dquot) +{ + struct util_dqblk *m = &dquot->dq_dqb; + struct v2r1_disk_dqblk *d = dp; + + d->dqb_ihardlimit = ext2fs_cpu_to_le64(m->dqb_ihardlimit); + d->dqb_isoftlimit = ext2fs_cpu_to_le64(m->dqb_isoftlimit); + d->dqb_bhardlimit = ext2fs_cpu_to_le64(m->dqb_bhardlimit); + d->dqb_bsoftlimit = ext2fs_cpu_to_le64(m->dqb_bsoftlimit); + d->dqb_curinodes = ext2fs_cpu_to_le64(m->dqb_curinodes); + d->dqb_curspace = ext2fs_cpu_to_le64(m->dqb_curspace); + d->dqb_itime = ext2fs_cpu_to_le64(m->dqb_itime); + d->dqb_btime = ext2fs_cpu_to_le64(m->dqb_btime); + d->dqb_id = ext2fs_cpu_to_le32(dquot->dq_id); + if (qtree_entry_unused(&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree, dp)) + d->dqb_itime = ext2fs_cpu_to_le64(1); +} + +static int v2r1_is_id(void *dp, struct dquot *dquot) +{ + struct v2r1_disk_dqblk *d = dp; + struct qtree_mem_dqinfo *info = + &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; + + if (qtree_entry_unused(info, dp)) + return 0; + return ext2fs_le32_to_cpu(d->dqb_id) == dquot->dq_id; +} + +static struct qtree_fmt_operations v2r1_fmt_ops = { + .mem2disk_dqblk = v2r1_mem2diskdqblk, + .disk2mem_dqblk = v2r1_disk2memdqblk, + .is_id = v2r1_is_id, +}; + +/* + * Copy dqinfo from disk to memory + */ +static inline void v2_disk2memdqinfo(struct util_dqinfo *m, + struct v2_disk_dqinfo *d) +{ + m->dqi_bgrace = ext2fs_le32_to_cpu(d->dqi_bgrace); + m->dqi_igrace = ext2fs_le32_to_cpu(d->dqi_igrace); + m->u.v2_mdqi.dqi_flags = ext2fs_le32_to_cpu(d->dqi_flags) & V2_DQF_MASK; + m->u.v2_mdqi.dqi_qtree.dqi_blocks = ext2fs_le32_to_cpu(d->dqi_blocks); + m->u.v2_mdqi.dqi_qtree.dqi_free_blk = + ext2fs_le32_to_cpu(d->dqi_free_blk); + m->u.v2_mdqi.dqi_qtree.dqi_free_entry = + ext2fs_le32_to_cpu(d->dqi_free_entry); +} + +/* + * Copy dqinfo from memory to disk + */ +static inline void v2_mem2diskdqinfo(struct v2_disk_dqinfo *d, + struct util_dqinfo *m) +{ + d->dqi_bgrace = ext2fs_cpu_to_le32(m->dqi_bgrace); + d->dqi_igrace = ext2fs_cpu_to_le32(m->dqi_igrace); + d->dqi_flags = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_flags & V2_DQF_MASK); + d->dqi_blocks = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_blocks); + d->dqi_free_blk = + ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_blk); + d->dqi_free_entry = + ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_entry); +} + +static int v2_read_header(struct quota_handle *h, struct v2_disk_dqheader *dqh) +{ + if (h->e2fs_read(&h->qh_qf, 0, dqh, sizeof(struct v2_disk_dqheader)) != + sizeof(struct v2_disk_dqheader)) + return 0; + + return 1; +} + +/* + * Check whether given quota file is in our format + */ +static int v2_check_file(struct quota_handle *h, int type, int fmt) +{ + struct v2_disk_dqheader dqh; + int file_magics[] = INITQMAGICS; + int be_magic; + + if (fmt != QFMT_VFS_V1) + return 0; + + if (!v2_read_header(h, &dqh)) + return 0; + + be_magic = ext2fs_be32_to_cpu((__force __be32)dqh.dqh_magic); + if (be_magic == file_magics[type]) { + log_err("Your quota file is stored in wrong endianity"); + return 0; + } + if (V2_VERSION != ext2fs_le32_to_cpu(dqh.dqh_version)) + return 0; + return 1; +} + +/* + * Open quotafile + */ +static int v2_init_io(struct quota_handle *h) +{ + struct v2_disk_dqinfo ddqinfo; + + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = + sizeof(struct v2r1_disk_dqblk); + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; + + /* Read information about quotafile */ + if (h->e2fs_read(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, + sizeof(ddqinfo)) != sizeof(ddqinfo)) + return -1; + v2_disk2memdqinfo(&h->qh_info, &ddqinfo); + return 0; +} + +/* + * Initialize new quotafile + */ +static int v2_new_io(struct quota_handle *h) +{ + int file_magics[] = INITQMAGICS; + struct v2_disk_dqheader ddqheader; + struct v2_disk_dqinfo ddqinfo; + + if (h->qh_fmt != QFMT_VFS_V1) + return -1; + + /* Write basic quota header */ + ddqheader.dqh_magic = ext2fs_cpu_to_le32(file_magics[h->qh_type]); + ddqheader.dqh_version = ext2fs_cpu_to_le32(V2_VERSION); + if (h->e2fs_write(&h->qh_qf, 0, &ddqheader, sizeof(ddqheader)) != + sizeof(ddqheader)) + return -1; + + /* Write information about quotafile */ + h->qh_info.dqi_bgrace = MAX_DQ_TIME; + h->qh_info.dqi_igrace = MAX_IQ_TIME; + h->qh_info.u.v2_mdqi.dqi_flags = 0; + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks = QT_TREEOFF + 1; + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_blk = 0; + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = 0; + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = + sizeof(struct v2r1_disk_dqblk); + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; + v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); + if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, + sizeof(ddqinfo)) != + sizeof(ddqinfo)) + return -1; + + return 0; +} + +/* + * Write information (grace times to file) + */ +static int v2_write_info(struct quota_handle *h) +{ + struct v2_disk_dqinfo ddqinfo; + + v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); + if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, sizeof(ddqinfo)) != + sizeof(ddqinfo)) + return -1; + + return 0; +} + +/* + * Read dquot from disk + */ +static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id) +{ + return qtree_read_dquot(h, id); +} + +/* + * Commit changes of dquot to disk - it might also mean deleting it when quota + * became fake one and user has no blocks. + * User can process use 'errno' to detect errstr. + */ +static int v2_commit_dquot(struct dquot *dquot) +{ + struct util_dqblk *b = &dquot->dq_dqb; + + if (!b->dqb_curspace && !b->dqb_curinodes && !b->dqb_bsoftlimit && + !b->dqb_isoftlimit && !b->dqb_bhardlimit && !b->dqb_ihardlimit) + qtree_delete_dquot(dquot); + else + qtree_write_dquot(dquot); + return 0; +} + +static int v2_scan_dquots(struct quota_handle *h, + int (*process_dquot) (struct dquot *, void *), + void *data) +{ + return qtree_scan_dquots(h, process_dquot, data); +} + +/* Report information about quotafile. + * TODO: Not used right now, but we should be able to use this when we add + * support to debugfs to read quota files. + */ +static int v2_report(struct quota_handle *h EXT2FS_ATTR((unused)), + int verbose EXT2FS_ATTR((unused))) +{ + log_err("Not Implemented."); + return -1; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libsupport/quotaio_v2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libsupport/quotaio_v2.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,54 @@ +/* + * + * Header file for disk format of new quotafile format + * + */ + +#ifndef GUARD_QUOTAIO_V2_H +#define GUARD_QUOTAIO_V2_H + +#include +#include "quotaio.h" + +/* Offset of info header in file */ +#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) +/* Supported version of quota-tree format */ +#define V2_VERSION 1 + +struct v2_disk_dqheader { + __le32 dqh_magic; /* Magic number identifying file */ + __le32 dqh_version; /* File version */ +} __attribute__ ((packed)); + +/* Flags for version specific files */ +#define V2_DQF_MASK 0x0000 /* Mask for all valid ondisk flags */ + +/* Header with type and version specific information */ +struct v2_disk_dqinfo { + __le32 dqi_bgrace; /* Time before block soft limit becomes + * hard limit */ + __le32 dqi_igrace; /* Time before inode soft limit becomes + * hard limit */ + __le32 dqi_flags; /* Flags for quotafile (DQF_*) */ + __le32 dqi_blocks; /* Number of blocks in file */ + __le32 dqi_free_blk; /* Number of first free block in the list */ + __le32 dqi_free_entry; /* Number of block with at least one + * free entry */ +} __attribute__ ((packed)); + +struct v2r1_disk_dqblk { + __le32 dqb_id; /* id this quota applies to */ + __le32 dqb_pad; + __le64 dqb_ihardlimit; /* absolute limit on allocated inodes */ + __le64 dqb_isoftlimit; /* preferred inode limit */ + __le64 dqb_curinodes; /* current # allocated inodes */ + __le64 dqb_bhardlimit; /* absolute limit on disk space + * (in QUOTABLOCK_SIZE) */ + __le64 dqb_bsoftlimit; /* preferred limit on disk space + * (in QUOTABLOCK_SIZE) */ + __le64 dqb_curspace; /* current space occupied (in bytes) */ + __le64 dqb_btime; /* time limit for excessive disk use */ + __le64 dqb_itime; /* time limit for excessive inode use */ +} __attribute__ ((packed)); + +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libuuid/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libuuid/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,16 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../../.. + +TARGET = libuuid.a libuuid.so +PC_FILENAME = libuuid +SRC_C = \ + clear.c compare.c copy.c gen_uuid.c isnull.c pack.c \ + parse.c tst_uuid.c unpack.c unparse.c uuid_time.c + +PRIVATE_INCDIR += \ + $(PKGDIR)/lib $(PKGDIR)/lib/libuuid \ + $(PKGDIR)/include/libuuid + +CONTRIB_INCDIR = libuuid + +include $(L4DIR)/mk/lib.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libuuid/clear.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libuuid/clear.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,44 @@ +/* + * clear.c -- Clear a UUID + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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 name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "config.h" +#include "string.h" + +#include "uuidP.h" + +void uuid_clear(uuid_t uu) +{ + memset(uu, 0, 16); +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libuuid/compare.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libuuid/compare.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,56 @@ +/* + * compare.c --- compare whether or not two UUID's are the same + * + * Returns 0 if the two UUID's are different, and 1 if they are the same. + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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 name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "config.h" +#include "uuidP.h" +#include + +#define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1); + +int uuid_compare(const uuid_t uu1, const uuid_t uu2) +{ + struct uuid uuid1, uuid2; + + uuid_unpack(uu1, &uuid1); + uuid_unpack(uu2, &uuid2); + + UUCMP(uuid1.time_low, uuid2.time_low); + UUCMP(uuid1.time_mid, uuid2.time_mid); + UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version); + UUCMP(uuid1.clock_seq, uuid2.clock_seq); + return memcmp(uuid1.node, uuid2.node, 6); +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libuuid/copy.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libuuid/copy.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,46 @@ +/* + * copy.c --- copy UUIDs + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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 name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "config.h" +#include "uuidP.h" + +void uuid_copy(uuid_t dst, const uuid_t src) +{ + unsigned char *cp1; + const unsigned char *cp2; + int i; + + for (i=0, cp1 = dst, cp2 = src; i < 16; i++) + *cp1++ = *cp2++; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libuuid/gen_uuid.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libuuid/gen_uuid.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,694 @@ +/* + * gen_uuid.c --- generate a DCE-compatible uuid + * + * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o. + * + * %Begin-Header% + * 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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 name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +/* + * Force inclusion of SVID stuff since we need it if we're compiling in + * gcc-wall wall mode + */ +#define _SVID_SOURCE +#define _DEFAULT_SOURCE /* since glibc 2.20 _SVID_SOURCE is deprecated */ + +#include "config.h" + +#ifdef _WIN32 +#define _WIN32_WINNT 0x0500 +#include +#define UUID MYUUID +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#include +#ifdef HAVE_SYS_FILE_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NET_IF_DL_H +#include +#endif +#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) +#include +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + +#include "uuidP.h" +#include "uuidd.h" + +#ifdef HAVE_SRANDOM +#define srand(x) srandom(x) +#define rand() random() +#endif + +#ifdef TLS +#define THREAD_LOCAL static TLS +#else +#define THREAD_LOCAL static +#endif + +#if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48) +#define DO_JRAND_MIX +THREAD_LOCAL unsigned short jrand_seed[3]; +#endif + +#ifdef _WIN32 +#ifndef USE_MINGW +static void gettimeofday (struct timeval *tv, void *dummy) +{ + FILETIME ftime; + uint64_t n; + + GetSystemTimeAsFileTime (&ftime); + n = (((uint64_t) ftime.dwHighDateTime << 32) + + (uint64_t) ftime.dwLowDateTime); + if (n) { + n /= 10; + n -= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000; + } + + tv->tv_sec = n / 1000000; + tv->tv_usec = n % 1000000; +} +#endif +#endif + +static int get_random_fd(void) +{ + struct timeval tv; + static int fd = -2; + int i; + + if (fd == -2) { + gettimeofday(&tv, 0); +#ifndef _WIN32 + fd = open("/dev/urandom", O_RDONLY); + if (fd == -1) + fd = open("/dev/random", O_RDONLY | O_NONBLOCK); + if (fd >= 0) { + i = fcntl(fd, F_GETFD); + if (i >= 0) + fcntl(fd, F_SETFD, i | FD_CLOEXEC); + } +#endif + srand(((unsigned)getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); +#ifdef DO_JRAND_MIX + jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF); + jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF); + jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16; +#endif + } + /* Crank the random number generator a few times */ + gettimeofday(&tv, 0); + for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) + rand(); + return fd; +} + + +/* + * Generate a series of random bytes. Use /dev/urandom if possible, + * and if not, use srandom/random. + */ +static void get_random_bytes(void *buf, int nbytes) +{ + int i, n = nbytes, fd = get_random_fd(); + int lose_counter = 0; + unsigned char *cp = buf; + + if (fd >= 0) { + while (n > 0) { + i = read(fd, cp, n); + if (i <= 0) { + if (lose_counter++ > 16) + break; + continue; + } + n -= i; + cp += i; + lose_counter = 0; + } + } + + /* + * We do this all the time, but this is the only source of + * randomness if /dev/random/urandom is out to lunch. + */ + for (cp = buf, i = 0; i < nbytes; i++) + *cp++ ^= (rand() >> 7) & 0xFF; +#ifdef DO_JRAND_MIX + { + unsigned short tmp_seed[3]; + + memcpy(tmp_seed, jrand_seed, sizeof(tmp_seed)); + jrand_seed[2] = jrand_seed[2] ^ syscall(__NR_gettid); + for (cp = buf, i = 0; i < nbytes; i++) + *cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF; + memcpy(jrand_seed, tmp_seed, + sizeof(jrand_seed) - sizeof(unsigned short)); + } +#endif + + return; +} + +/* + * Get the ethernet hardware address, if we can find it... + * + * XXX for a windows version, probably should use GetAdaptersInfo: + * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451 + * commenting out get_node_id just to get gen_uuid to compile under windows + * is not the right way to go! + */ +static int get_node_id(unsigned char *node_id) +{ +#ifdef HAVE_NET_IF_H + int sd; + struct ifreq ifr, *ifrp; + struct ifconf ifc; + char buf[1024]; + int n, i; + unsigned char *a; +#ifdef HAVE_NET_IF_DL_H + struct sockaddr_dl *sdlp; +#endif + +/* + * BSD 4.4 defines the size of an ifreq to be + * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len + * However, under earlier systems, sa_len isn't present, so the size is + * just sizeof(struct ifreq) + */ +#ifdef HAVE_SA_LEN +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif +#define ifreq_size(i) max(sizeof(struct ifreq),\ + sizeof((i).ifr_name)+(i).ifr_addr.sa_len) +#else +#define ifreq_size(i) sizeof(struct ifreq) +#endif /* HAVE_SA_LEN*/ + + sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sd < 0) { + return -1; + } + memset(buf, 0, sizeof(buf)); + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) { + close(sd); + return -1; + } + n = ifc.ifc_len; + for (i = 0; i < n; i+= ifreq_size(*ifrp) ) { + ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); + strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); +#ifdef SIOCGIFHWADDR + if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) + continue; + a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; +#else +#ifdef SIOCGENADDR + if (ioctl(sd, SIOCGENADDR, &ifr) < 0) + continue; + a = (unsigned char *) ifr.ifr_enaddr; +#else +#ifdef HAVE_NET_IF_DL_H + sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr; + if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6)) + continue; + a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen]; +#else + /* + * XXX we don't have a way of getting the hardware + * address + */ + close(sd); + return 0; +#endif /* HAVE_NET_IF_DL_H */ +#endif /* SIOCGENADDR */ +#endif /* SIOCGIFHWADDR */ + if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) + continue; + if (node_id) { + memcpy(node_id, a, 6); + close(sd); + return 1; + } + } + close(sd); +#endif + return 0; +} + +/* Assume that the gettimeofday() has microsecond granularity */ +#define MAX_ADJUSTMENT 10 + +static int get_clock(uint32_t *clock_high, uint32_t *clock_low, + uint16_t *ret_clock_seq, int *num) +{ + THREAD_LOCAL int adjustment = 0; + THREAD_LOCAL struct timeval last = {0, 0}; + THREAD_LOCAL int state_fd = -2; + THREAD_LOCAL FILE *state_f; + THREAD_LOCAL uint16_t clock_seq; + struct timeval tv; +#ifndef _WIN32 + struct flock fl; +#endif + uint64_t clock_reg; + mode_t save_umask; + int len; + + if (state_fd == -2) { + save_umask = umask(0); + state_fd = open("/var/lib/libuuid/clock.txt", + O_RDWR|O_CREAT, 0660); + (void) umask(save_umask); + if (state_fd >= 0) { + state_f = fdopen(state_fd, "r+"); + if (!state_f) { + close(state_fd); + state_fd = -1; + } + } + } +#ifndef _WIN32 + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_pid = 0; + if (state_fd >= 0) { + rewind(state_f); + while (fcntl(state_fd, F_SETLKW, &fl) < 0) { + if ((errno == EAGAIN) || (errno == EINTR)) + continue; + fclose(state_f); + state_fd = -1; + break; + } + } +#endif + if (state_fd >= 0) { + unsigned int cl; + unsigned long tv1, tv2; + int a; + + if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n", + &cl, &tv1, &tv2, &a) == 4) { + clock_seq = cl & 0x3FFF; + last.tv_sec = tv1; + last.tv_usec = tv2; + adjustment = a; + } + } + + if ((last.tv_sec == 0) && (last.tv_usec == 0)) { + get_random_bytes(&clock_seq, sizeof(clock_seq)); + clock_seq &= 0x3FFF; + gettimeofday(&last, 0); + last.tv_sec--; + } + +try_again: + gettimeofday(&tv, 0); + if ((tv.tv_sec < last.tv_sec) || + ((tv.tv_sec == last.tv_sec) && + (tv.tv_usec < last.tv_usec))) { + clock_seq = (clock_seq+1) & 0x3FFF; + adjustment = 0; + last = tv; + } else if ((tv.tv_sec == last.tv_sec) && + (tv.tv_usec == last.tv_usec)) { + if (adjustment >= MAX_ADJUSTMENT) + goto try_again; + adjustment++; + } else { + adjustment = 0; + last = tv; + } + + clock_reg = tv.tv_usec*10 + adjustment; + clock_reg += ((uint64_t) tv.tv_sec)*10000000; + clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; + + if (num && (*num > 1)) { + adjustment += *num - 1; + last.tv_usec += adjustment / 10; + adjustment = adjustment % 10; + last.tv_sec += last.tv_usec / 1000000; + last.tv_usec = last.tv_usec % 1000000; + } + + if (state_fd > 0) { + rewind(state_f); + len = fprintf(state_f, + "clock: %04x tv: %016lu %08lu adj: %08d\n", + clock_seq, last.tv_sec, (long)last.tv_usec, + adjustment); + fflush(state_f); + if (ftruncate(state_fd, len) < 0) { + fprintf(state_f, " \n"); + fflush(state_f); + } + rewind(state_f); +#ifndef _WIN32 + fl.l_type = F_UNLCK; + if (fcntl(state_fd, F_SETLK, &fl) < 0) { + fclose(state_f); + state_fd = -1; + } +#endif + } + + *clock_high = clock_reg >> 32; + *clock_low = clock_reg; + *ret_clock_seq = clock_seq; + return 0; +} + +#if defined(USE_UUIDD) && defined(HAVE_SYS_UN_H) +static ssize_t read_all(int fd, char *buf, size_t count) +{ + ssize_t ret; + ssize_t c = 0; + int tries = 0; + + memset(buf, 0, count); + while (count > 0) { + ret = read(fd, buf, count); + if (ret <= 0) { + if ((errno == EAGAIN || errno == EINTR || ret == 0) && + (tries++ < 5)) + continue; + return c ? c : -1; + } + if (ret > 0) + tries = 0; + count -= ret; + buf += ret; + c += ret; + } + return c; +} + +/* + * Close all file descriptors + */ +static void close_all_fds(void) +{ + int i, max; + +#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) + max = sysconf(_SC_OPEN_MAX); +#elif defined(HAVE_GETDTABLESIZE) + max = getdtablesize(); +#elif defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) + struct rlimit rl; + + getrlimit(RLIMIT_NOFILE, &rl); + max = rl.rlim_cur; +#else + max = OPEN_MAX; +#endif + + for (i=0; i < max; i++) { + close(i); + if (i <= 2) + open("/dev/null", O_RDWR); + } +} +#endif /* defined(USE_UUIDD) && defined(HAVE_SYS_UN_H) */ + +#if __GNUC_PREREQ (4, 6) +#pragma GCC diagnostic push +#if !defined(USE_UUIDD) || !defined(HAVE_SYS_UN_H) +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif +#endif +/* + * Try using the uuidd daemon to generate the UUID + * + * Returns 0 on success, non-zero on failure. + */ +static int get_uuid_via_daemon(int op, uuid_t out, int *num) +{ +#if defined(USE_UUIDD) && defined(HAVE_SYS_UN_H) + char op_buf[64]; + int op_len; + int s; + ssize_t ret; + int32_t reply_len = 0, expected = 16; + struct sockaddr_un srv_addr; + struct stat st; + pid_t pid; + static const char *uuidd_path = UUIDD_PATH; + static int access_ret = -2; + static int start_attempts = 0; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return -1; + + srv_addr.sun_family = AF_UNIX; + strcpy(srv_addr.sun_path, UUIDD_SOCKET_PATH); + + if (connect(s, (const struct sockaddr *) &srv_addr, + sizeof(struct sockaddr_un)) < 0) { + if (access_ret == -2) + access_ret = access(uuidd_path, X_OK); + if (access_ret == 0) + access_ret = stat(uuidd_path, &st); + if (access_ret == 0 && (st.st_mode & (S_ISUID | S_ISGID)) == 0) + access_ret = access(UUIDD_DIR, W_OK); + if (access_ret == 0 && start_attempts++ < 5) { + if ((pid = fork()) == 0) { + close_all_fds(); + execl(uuidd_path, "uuidd", "-qT", "300", + (char *) NULL); + exit(1); + } + (void) waitpid(pid, 0, 0); + if (connect(s, (const struct sockaddr *) &srv_addr, + sizeof(struct sockaddr_un)) < 0) + goto fail; + } else + goto fail; + } + op_buf[0] = op; + op_len = 1; + if (op == UUIDD_OP_BULK_TIME_UUID) { + memcpy(op_buf+1, num, sizeof(*num)); + op_len += sizeof(*num); + expected += sizeof(*num); + } + + ret = write(s, op_buf, op_len); + if (ret < 1) + goto fail; + + ret = read_all(s, (char *) &reply_len, sizeof(reply_len)); + if (ret < 0) + goto fail; + + if (reply_len != expected) + goto fail; + + ret = read_all(s, op_buf, reply_len); + + if (op == UUIDD_OP_BULK_TIME_UUID) + memcpy(op_buf+16, num, sizeof(int)); + + memcpy(out, op_buf, 16); + + close(s); + return ((ret == expected) ? 0 : -1); + +fail: + close(s); +#endif + return -1; +} +#if __GNUC_PREREQ (4, 6) +#pragma GCC diagnostic pop +#endif + +void uuid__generate_time(uuid_t out, int *num) +{ + static unsigned char node_id[6]; + static int has_init = 0; + struct uuid uu; + uint32_t clock_mid; + + if (!has_init) { + if (get_node_id(node_id) <= 0) { + get_random_bytes(node_id, 6); + /* + * Set multicast bit, to prevent conflicts + * with IEEE 802 addresses obtained from + * network cards + */ + node_id[0] |= 0x01; + } + has_init = 1; + } + get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num); + uu.clock_seq |= 0x8000; + uu.time_mid = (uint16_t) clock_mid; + uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000; + memcpy(uu.node, node_id, 6); + uuid_pack(&uu, out); +} + +void uuid_generate_time(uuid_t out) +{ +#ifdef TLS + THREAD_LOCAL int num = 0; + THREAD_LOCAL struct uuid uu; + THREAD_LOCAL time_t last_time = 0; + time_t now; + + if (num > 0) { + now = time(0); + if (now > last_time+1) + num = 0; + } + if (num <= 0) { + num = 1000; + if (get_uuid_via_daemon(UUIDD_OP_BULK_TIME_UUID, + out, &num) == 0) { + last_time = time(0); + uuid_unpack(out, &uu); + num--; + return; + } + num = 0; + } + if (num > 0) { + uu.time_low++; + if (uu.time_low == 0) { + uu.time_mid++; + if (uu.time_mid == 0) + uu.time_hi_and_version++; + } + num--; + uuid_pack(&uu, out); + return; + } +#else + if (get_uuid_via_daemon(UUIDD_OP_TIME_UUID, out, 0) == 0) + return; +#endif + + uuid__generate_time(out, 0); +} + + +void uuid__generate_random(uuid_t out, int *num) +{ + uuid_t buf; + struct uuid uu; + int i, n; + + if (!num || !*num) + n = 1; + else + n = *num; + + for (i = 0; i < n; i++) { + get_random_bytes(buf, sizeof(buf)); + uuid_unpack(buf, &uu); + + uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; + uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) + | 0x4000; + uuid_pack(&uu, out); + out += sizeof(uuid_t); + } +} + +void uuid_generate_random(uuid_t out) +{ + int num = 1; + /* No real reason to use the daemon for random uuid's -- yet */ + + uuid__generate_random(out, &num); +} + + +/* + * This is the generic front-end to uuid_generate_random and + * uuid_generate_time. It uses uuid_generate_random only if + * /dev/urandom is available, since otherwise we won't have + * high-quality randomness. + */ +void uuid_generate(uuid_t out) +{ + if (get_random_fd() >= 0) + uuid_generate_random(out); + else + uuid_generate_time(out); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libuuid/isnull.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libuuid/isnull.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,49 @@ +/* + * isnull.c --- Check whether or not the UUID is null + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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 name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "config.h" +#include "uuidP.h" + +/* Returns 1 if the uuid is the NULL uuid */ +int uuid_is_null(const uuid_t uu) +{ + const unsigned char *cp; + int i; + + for (i=0, cp = uu; i < 16; i++) + if (*cp++) + return 0; + return 1; +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libuuid/pack.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libuuid/pack.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,70 @@ +/* + * Internal routine for packing UUID's + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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 name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "config.h" +#include +#include "uuidP.h" + +void uuid_pack(const struct uuid *uu, uuid_t ptr) +{ + uint32_t tmp; + unsigned char *out = ptr; + + tmp = uu->time_low; + out[3] = (unsigned char) tmp; + tmp >>= 8; + out[2] = (unsigned char) tmp; + tmp >>= 8; + out[1] = (unsigned char) tmp; + tmp >>= 8; + out[0] = (unsigned char) tmp; + + tmp = uu->time_mid; + out[5] = (unsigned char) tmp; + tmp >>= 8; + out[4] = (unsigned char) tmp; + + tmp = uu->time_hi_and_version; + out[7] = (unsigned char) tmp; + tmp >>= 8; + out[6] = (unsigned char) tmp; + + tmp = uu->clock_seq; + out[9] = (unsigned char) tmp; + tmp >>= 8; + out[8] = (unsigned char) tmp; + + memcpy(out+10, uu->node, 6); +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libuuid/parse.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libuuid/parse.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,80 @@ +/* + * parse.c --- UUID parsing + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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 name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include +#include + +#include "uuidP.h" + +int uuid_parse(const char *in, uuid_t uu) +{ + struct uuid uuid; + int i; + const char *cp; + char buf[3]; + + if (strlen(in) != 36) + return -1; + for (i=0, cp = in; i <= 36; i++,cp++) { + if ((i == 8) || (i == 13) || (i == 18) || + (i == 23)) { + if (*cp == '-') + continue; + else + return -1; + } + if (i== 36) + if (*cp == 0) + continue; + if (!isxdigit(*cp)) + return -1; + } + uuid.time_low = strtoul(in, NULL, 16); + uuid.time_mid = strtoul(in+9, NULL, 16); + uuid.time_hi_and_version = strtoul(in+14, NULL, 16); + uuid.clock_seq = strtoul(in+19, NULL, 16); + cp = in+24; + buf[2] = 0; + for (i=0; i < 6; i++) { + buf[0] = *cp++; + buf[1] = *cp++; + uuid.node[i] = strtoul(buf, NULL, 16); + } + + uuid_pack(&uuid, uu); + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libuuid/tst_uuid.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libuuid/tst_uuid.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,199 @@ +/* + * tst_uuid.c --- test program from the UUID library + * + * Copyright (C) 1996, 1997, 1998 Theodore Ts'o. + * + * %Begin-Header% + * 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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 name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "config.h" + +#ifdef _WIN32 +#define _WIN32_WINNT 0x0500 +#include +#define UUID MYUUID +#endif + +#include +#include + +#include + +static int test_uuid(const char * uuid, int isValid) +{ + static const char * validStr[2] = {"invalid", "valid"}; + uuid_t uuidBits; + int parsedOk; + + parsedOk = uuid_parse(uuid, uuidBits) == 0; + + printf("%s is %s", uuid, validStr[isValid]); + if (parsedOk != isValid) { + printf(" but uuid_parse says %s\n", validStr[parsedOk]); + return 1; + } + printf(", OK\n"); + return 0; +} + +#ifdef __GNUC__ +#define ATTR(x) __attribute__(x) +#else +#define ATTR(x) +#endif + +int +main(int argc ATTR((unused)) , char **argv ATTR((unused))) +{ + uuid_t buf, tst; + char str[100]; + struct timeval tv; + time_t time_reg, time_gen; + unsigned char *cp; + int i; + int failed = 0; + int type, variant; + + uuid_generate(buf); + uuid_unparse(buf, str); + printf("UUID generate = %s\n", str); + printf("UUID: "); + for (i=0, cp = (unsigned char *) &buf; i < 16; i++) { + printf("%02x", *cp++); + } + printf("\n"); + type = uuid_type(buf); variant = uuid_variant(buf); + printf("UUID type = %d, UUID variant = %d\n", type, variant); + if (variant != UUID_VARIANT_DCE) { + printf("Incorrect UUID Variant; was expecting DCE!\n"); + failed++; + } + printf("\n"); + + uuid_generate_random(buf); + uuid_unparse(buf, str); + printf("UUID random string = %s\n", str); + printf("UUID: "); + for (i=0, cp = (unsigned char *) &buf; i < 16; i++) { + printf("%02x", *cp++); + } + printf("\n"); + type = uuid_type(buf); + variant = uuid_variant(buf); + printf("UUID type = %d, UUID variant = %d\n", type, variant); + if (variant != UUID_VARIANT_DCE) { + printf("Incorrect UUID Variant; was expecting DCE!\n"); + failed++; + } + if (type != 4) { + printf("Incorrect UUID type; was expecting " + "4 (random type)!\n"); + failed++; + } + printf("\n"); + + time_gen = time(0); + uuid_generate_time(buf); + uuid_unparse(buf, str); + printf("UUID string = %s\n", str); + printf("UUID time: "); + for (i=0, cp = (unsigned char *) &buf; i < 16; i++) { + printf("%02x", *cp++); + } + printf("\n"); + type = uuid_type(buf); + variant = uuid_variant(buf); + printf("UUID type = %d, UUID variant = %d\n", type, variant); + if (variant != UUID_VARIANT_DCE) { + printf("Incorrect UUID Variant; was expecting DCE!\n"); + failed++; + } + if (type != 1) { + printf("Incorrect UUID type; was expecting " + "1 (time-based type)!\\n"); + failed++; + } + + tv.tv_sec = 0; + tv.tv_usec = 0; + time_reg = uuid_time(buf, &tv); + printf("UUID generated at %lu reports %lu (%ld.%ld)\n", + time_gen, time_reg, tv.tv_sec, (long)tv.tv_usec); + /* allow 1s margin in case of rollover between sampling + * the current time and when the UUID is generated. */ + if (time_reg > time_gen + 1) { + printf("UUID time comparison failed!\n"); + failed++; + } else { + printf("UUID time comparison succeeded.\n"); + } + + if (uuid_parse(str, tst) < 0) { + printf("UUID parse failed\n"); + failed++; + } + if (!uuid_compare(buf, tst)) { + printf("UUID parse and compare succeeded.\n"); + } else { + printf("UUID parse and compare failed!\n"); + failed++; + } + uuid_clear(tst); + if (uuid_is_null(tst)) + printf("UUID clear and is null succeeded.\n"); + else { + printf("UUID clear and is null failed!\n"); + failed++; + } + uuid_copy(buf, tst); + if (!uuid_compare(buf, tst)) + printf("UUID copy and compare succeeded.\n"); + else { + printf("UUID copy and compare failed!\n"); + failed++; + } + + failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981b", 1); + failed += test_uuid("84949CC5-4701-4A84-895B-354C584A981B", 1); + failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981bc", 0); + failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981", 0); + failed += test_uuid("84949cc5x4701-4a84-895b-354c584a981b", 0); + failed += test_uuid("84949cc504701-4a84-895b-354c584a981b", 0); + failed += test_uuid("84949cc5-470104a84-895b-354c584a981b", 0); + failed += test_uuid("84949cc5-4701-4a840895b-354c584a981b", 0); + failed += test_uuid("84949cc5-4701-4a84-895b0354c584a981b", 0); + failed += test_uuid("g4949cc5-4701-4a84-895b-354c584a981b", 0); + failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981g", 0); + + if (failed) { + printf("%d failures.\n", failed); + exit(1); + } + return 0; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libuuid/unpack.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libuuid/unpack.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,64 @@ +/* + * Internal routine for unpacking UUID + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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 name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "config.h" +#include +#include "uuidP.h" + +void uuid_unpack(const uuid_t in, struct uuid *uu) +{ + const uint8_t *ptr = in; + uint32_t tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + tmp = (tmp << 8) | *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_low = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_mid = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_hi_and_version = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->clock_seq = tmp; + + memcpy(uu->node, ptr, 6); +} + diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libuuid/unparse.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libuuid/unparse.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,77 @@ +/* + * unparse.c -- convert a UUID to string + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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 name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "config.h" +#include + +#include "uuidP.h" + +static const char *fmt_lower = + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"; + +static const char *fmt_upper = + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"; + +#ifdef UUID_UNPARSE_DEFAULT_UPPER +#define FMT_DEFAULT fmt_upper +#else +#define FMT_DEFAULT fmt_lower +#endif + +static void uuid_unparse_x(const uuid_t uu, char *out, const char *fmt) +{ + struct uuid uuid; + + uuid_unpack(uu, &uuid); + sprintf(out, fmt, + uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, + uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, + uuid.node[0], uuid.node[1], uuid.node[2], + uuid.node[3], uuid.node[4], uuid.node[5]); +} + +void uuid_unparse_lower(const uuid_t uu, char *out) +{ + uuid_unparse_x(uu, out, fmt_lower); +} + +void uuid_unparse_upper(const uuid_t uu, char *out) +{ + uuid_unparse_x(uu, out, fmt_upper); +} + +void uuid_unparse(const uuid_t uu, char *out) +{ + uuid_unparse_x(uu, out, FMT_DEFAULT); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libuuid/uuidP.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libuuid/uuidP.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,74 @@ +/* + * uuid.h -- private header file for uuids + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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 name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +/* PAUL: Added here to avoid redefinition attempts. */ +#include + +#ifdef HAVE_INTTYPES_H +#include +#else +#include +#endif +#include + +#include + +/* + * Offset between 15-Oct-1582 and 1-Jan-70 + */ +#define TIME_OFFSET_HIGH 0x01B21DD2 +#define TIME_OFFSET_LOW 0x13814000 + +struct uuid { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint16_t clock_seq; + uint8_t node[6]; +}; + +#ifndef __GNUC_PREREQ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +#define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +#define __GNUC_PREREQ(maj, min) 0 +#endif +#endif + +/* + * prototypes + */ +void uuid_pack(const struct uuid *uu, uuid_t ptr); +void uuid_unpack(const uuid_t in, struct uuid *uu); diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libuuid/uuid_time.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libuuid/uuid_time.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,173 @@ +/* + * uuid_time.c --- Interpret the time field from a uuid. This program + * violates the UUID abstraction barrier by reaching into the guts + * of a UUID and interpreting it. + * + * Copyright (C) 1998, 1999 Theodore Ts'o. + * + * %Begin-Header% + * 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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 name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "config.h" + +#ifdef _WIN32 +#define _WIN32_WINNT 0x0500 +#include +#define UUID MYUUID +#endif + +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include + +#include "uuidP.h" + +time_t uuid_time(const uuid_t uu, struct timeval *ret_tv) +{ + struct timeval tv; + struct uuid uuid; + uint32_t high; + uint64_t clock_reg; + + uuid_unpack(uu, &uuid); + + high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16); + clock_reg = uuid.time_low | ((uint64_t) high << 32); + + clock_reg -= (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; + tv.tv_sec = clock_reg / 10000000; + tv.tv_usec = (clock_reg % 10000000) / 10; + + if (ret_tv) + *ret_tv = tv; + + return tv.tv_sec; +} + +int uuid_type(const uuid_t uu) +{ + struct uuid uuid; + + uuid_unpack(uu, &uuid); + return ((uuid.time_hi_and_version >> 12) & 0xF); +} + +int uuid_variant(const uuid_t uu) +{ + struct uuid uuid; + int var; + + uuid_unpack(uu, &uuid); + var = uuid.clock_seq; + + if ((var & 0x8000) == 0) + return UUID_VARIANT_NCS; + if ((var & 0x4000) == 0) + return UUID_VARIANT_DCE; + if ((var & 0x2000) == 0) + return UUID_VARIANT_MICROSOFT; + return UUID_VARIANT_OTHER; +} + +#ifdef DEBUG +static const char *variant_string(int variant) +{ + switch (variant) { + case UUID_VARIANT_NCS: + return "NCS"; + case UUID_VARIANT_DCE: + return "DCE"; + case UUID_VARIANT_MICROSOFT: + return "Microsoft"; + default: + return "Other"; + } +} + + +int +main(int argc, char **argv) +{ + uuid_t buf; + time_t time_reg; + struct timeval tv; + int type, variant; + + if (argc != 2) { + fprintf(stderr, "Usage: %s uuid\n", argv[0]); + exit(1); + } + if (uuid_parse(argv[1], buf)) { + fprintf(stderr, "Invalid UUID: %s\n", argv[1]); + exit(1); + } + variant = uuid_variant(buf); + type = uuid_type(buf); + time_reg = uuid_time(buf, &tv); + + printf("UUID variant is %d (%s)\n", variant, variant_string(variant)); + if (variant != UUID_VARIANT_DCE) { + printf("Warning: This program only knows how to interpret " + "DCE UUIDs.\n\tThe rest of the output is likely " + "to be incorrect!!\n"); + } + printf("UUID type is %d", type); + switch (type) { + case 1: + printf(" (time based)\n"); + break; + case 2: + printf(" (DCE)\n"); + break; + case 3: + printf(" (name-based)\n"); + break; + case 4: + printf(" (random)\n"); + break; + default: + printf("\n"); + } + if (type != 1) { + printf("Warning: not a time-based UUID, so UUID time " + "decoding will likely not work!\n"); + } + printf("UUID time is: (%ld, %ld): %s\n", tv.tv_sec, (long)tv.tv_usec, + ctime(&time_reg)); + + return 0; +} +#endif diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/libuuid/uuidd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/libuuid/uuidd.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,54 @@ +/* + * Definitions used by the uuidd daemon + * + * Copyright (C) 2007 Theodore Ts'o. + * + * %Begin-Header% + * 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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 name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#ifndef _UUID_UUIDD_H +#define _UUID_UUIDD_H + +#define UUIDD_DIR "/var/lib/libuuid" +#define UUIDD_SOCKET_PATH UUIDD_DIR "/request" +#define UUIDD_PIDFILE_PATH UUIDD_DIR "/uuidd.pid" +#define UUIDD_PATH "/usr/sbin/uuidd" + +#define UUIDD_OP_GETPID 0 +#define UUIDD_OP_GET_MAXOP 1 +#define UUIDD_OP_TIME_UUID 2 +#define UUIDD_OP_RANDOM_UUID 3 +#define UUIDD_OP_BULK_TIME_UUID 4 +#define UUIDD_OP_BULK_RANDOM_UUID 5 +#define UUIDD_MAX_OP UUIDD_OP_BULK_RANDOM_UUID + +extern void uuid__generate_time(uuid_t out, int *num); +extern void uuid__generate_random(uuid_t out, int *num); + +#endif /* _UUID_UUID_H */ diff -r 40dc1cbd5356 -r 49d8e9637cdb libext2fs/lib/version.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libext2fs/lib/version.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,11 @@ +/* + * version.h --- controls the version number printed by the e2fs + * programs. + * + * Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + * 2004, 2005, 2006, 2007, 2008, 2009, 2010 by Theodore Ts'o. This + * file may be redistributed under the GNU Public License v2. + */ + +#define E2FSPROGS_VERSION "1.44.5" +#define E2FSPROGS_DATE "15-Dec-2018" diff -r 40dc1cbd5356 -r 49d8e9637cdb libfsclient/lib/src/Makefile --- a/libfsclient/lib/src/Makefile Sun Aug 22 22:37:55 2021 +0200 +++ b/libfsclient/lib/src/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -6,7 +6,7 @@ # Locations for interface input and generated output. -IDL_DIR = $(L4DIR)/pkg/libsystypes/idl +IDL_DIR = $(PKGDIR)/../libsystypes/idl IDL_MK_DIR = $(L4DIR)/idl4re/mk IDL_BUILD_DIR = . IDL_EXPORT_DIR = . diff -r 40dc1cbd5356 -r 49d8e9637cdb libfsserver/lib/Makefile --- a/libfsserver/lib/Makefile Sun Aug 22 22:37:55 2021 +0200 +++ b/libfsserver/lib/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -6,7 +6,7 @@ # Locations for interface input and generated output. -IDL_DIR = $(L4DIR)/pkg/libsystypes/idl +IDL_DIR = $(PKGDIR)/../libsystypes/idl IDL_MK_DIR = $(L4DIR)/idl4re/mk IDL_BUILD_DIR = . IDL_EXPORT_DIR = $(OBJ_BASE)/include/contrib/$(CONTRIB_INCDIR)/fsserver diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/Control --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/Control Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,3 @@ +requires: libc libsystypes +provides: libipc +maintainer: paul@boddie.org.uk diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,4 @@ +PKGDIR ?= . +L4DIR ?= $(PKGDIR)/../../.. + +include $(L4DIR)/mk/subdir.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/docs/COPYING-GPL-2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/docs/COPYING-GPL-2 Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,1 @@ +LICENCE.txt \ No newline at end of file diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/docs/COPYING.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/docs/COPYING.txt Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,22 @@ +Licence Agreement +----------------- + +All original work in this distribution is covered by the following copyright +and licensing information: + +Copyright (C) 2018, 2019 Paul Boddie + +This software 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 software 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 library; see the file LICENCE.txt +If not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/docs/LICENCE.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/docs/LICENCE.txt Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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 + + 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) + + 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. + +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) year 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 Lesser General +Public License instead of this License. diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/include/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,7 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../../.. + +PKGNAME = libipc +CONTRIB_HEADERS = 1 + +include $(L4DIR)/mk/include.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/include/ipc/cap_alloc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/include/ipc/cap_alloc.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,32 @@ +/* + * Capability allocation and management. + * + * Copyright (C) 2019, 2021 Paul Boddie + * + * 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 + */ + +#pragma once + +#include + +EXTERN_C_BEGIN + +l4_cap_idx_t ipc_cap_alloc(void); +int ipc_cap_free(l4_cap_idx_t cap); +int ipc_cap_free_um(l4_cap_idx_t cap); + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/include/ipc/direct.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/include/ipc/direct.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,40 @@ +/* + * Interprocess communication operations. + * + * Copyright (C) 2018, 2019 Paul Boddie + * + * 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 + */ + +#pragma once + +#include +#include +#include + + + +EXTERN_C_BEGIN + +/* Direct operations. */ + +long ipc_expect_capabilities(int number); +long ipc_expect_capability(int item); +void ipc_export_capability(l4_msgtag_t tag, int item, l4_cap_idx_t ref); +long ipc_import_capability(l4_msgtag_t tag, int item, l4_cap_idx_t *ref); +long ipc_import_dataspace(l4_msgtag_t tag, int item, l4re_ds_t *mem, l4_addr_t *addr); + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/include/ipc/factory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/include/ipc/factory.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,45 @@ +/* + * Factory-related data types. + * + * Copyright (C) 2019 Paul Boddie + * + * 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 + */ + +#pragma once + +#include + +#include + + + +EXTERN_C_BEGIN + +/* Supporting data types for factory invocations. */ + +typedef unsigned long unsigned_long; + +ipc_varg_typedef(long, ipc_varg(long)) +ipc_varg_typedef(unsigned_long, ipc_varg(unsigned_long)) + +#define ipc_varg_long(value) \ +ipc_varg_mword(ipc_varg(long), value) + +#define ipc_varg_unsigned_long(value) \ +ipc_varg_umword(ipc_varg(unsigned_long), value) + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/include/ipc/irq.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/include/ipc/irq.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,37 @@ +/* + * Interrupt request handling. + * + * Copyright (C) 2018, 2019 Paul Boddie + * + * 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 + */ + +#pragma once + +#include +#include + + + +EXTERN_C_BEGIN + +/* IRQ operations. */ + +long ipc_create_irq(l4_cap_idx_t *irq); +l4_msgtag_t ipc_init_irq(l4_cap_idx_t irq); +long ipc_bind_irq(l4_cap_idx_t irq, l4_umword_t id, l4_cap_idx_t thread); + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/include/ipc/macros_ipc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/include/ipc/macros_ipc.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,38 @@ +/* + * Interprocess communication macros. + * + * Copyright (C) 2019 Paul Boddie + * + * 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 + */ + +#pragma once + +/* Count the size of an array. */ + +#define VA_ARGCOUNT(TYPE, ARGS) (sizeof(ARGS) / sizeof(TYPE)) + +/* Prepare an array from a variable argument list. */ + +#define VA_ARGLIST(TYPE, ...) ((TYPE []) {__VA_ARGS__}) + +/* Assign array members. */ + +#define ARRAY_ASSIGN(TO, TYPE, ...) \ + memcpy(TO, VA_ARGLIST(TYPE, __VA_ARGS__), \ + sizeof(VA_ARGLIST(TYPE, __VA_ARGS__))) + +#define ipc_set_registers(TO, ...) ARRAY_ASSIGN(TO, l4_umword_t, __VA_ARGS__) diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/include/ipc/mem_ipc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/include/ipc/mem_ipc.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,35 @@ +/* + * Memory sharing abstractions. + * + * Copyright (C) 2018, 2019, 2021 Paul Boddie + * + * 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 + */ + +#pragma once + +#include +#include + +EXTERN_C_BEGIN + +long ipc_allocate(unsigned long size, void **addr, l4re_ds_t *ds); +long ipc_new_dataspace(l4_cap_idx_t cap, l4_mword_t size, l4_umword_t flags, l4_umword_t align); +long ipc_attach_dataspace(l4re_ds_t ds, unsigned long size, void **addr); +long ipc_detach_dataspace(void *addr); +long ipc_dataspace_size(l4_cap_idx_t cap, unsigned long *size); + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/include/ipc/message.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/include/ipc/message.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,142 @@ +/* + * Interprocess communication message abstraction. + * + * Copyright (C) 2018, 2019, 2021 Paul Boddie + * + * 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 + */ + +#pragma once + +#include +#include +#include +#include + +#include + + + +EXTERN_C_BEGIN + +/* Message abstraction. */ + +typedef struct +{ + /* Common virtual registers. */ + + l4_buf_regs_t bregs; + l4_msg_regs_t mregs; + + /* Input details. */ + + l4_msgtag_t tag; + unsigned int expected_items; + + /* Output details. */ + + unsigned int words; + unsigned int items; + + /* Items transferred and not retained. */ + + unsigned int discarded_items; + l4_cap_idx_t to_discard[L4_UTCB_GENERIC_DATA_SIZE]; + + /* Message label overriding. */ + + l4_umword_t new_label; + + /* Server control. */ + + int terminating; + +} ipc_message_t; + + + +/* Special status codes. */ + +#define IPC_MESSAGE_SENT 0x01d10000 + +/* Capability annotations. */ + +#define IPC_DISCARD_CAP_FLAG (1 << (L4_CAP_SHIFT - 2)) +#define discard_cap(x) (x | IPC_DISCARD_CAP_FLAG) + + + +/* Message operations. */ + +/* Lifecycle operations. */ + +void ipc_message_new(ipc_message_t *msg); +long ipc_message_expect(ipc_message_t *msg, unsigned int expected_items); +void ipc_message_request(ipc_message_t *msg, int op, l4_cap_idx_t endpoint); +void ipc_message_send(ipc_message_t *msg, int op, l4_cap_idx_t endpoint); +void ipc_message_wait(ipc_message_t *msg, l4_umword_t *label); +void ipc_message_reply(ipc_message_t *msg); +void ipc_message_discard(ipc_message_t *msg); +void ipc_message_free(ipc_message_t *msg); + +/* Helper operations. */ + +void ipc_message_open(ipc_message_t *msg); +void ipc_message_prepare(ipc_message_t *msg); +void ipc_message_preserve_buffer_registers(ipc_message_t *msg); +void ipc_message_preserve_message_registers(ipc_message_t *msg); +void ipc_message_reset(ipc_message_t *msg); +void ipc_message_restore_buffer_registers(ipc_message_t *msg); +void ipc_message_restore_message_registers(ipc_message_t *msg); + +/* Population operations. */ + +void ipc_message_add_capability(ipc_message_t *msg, l4_cap_idx_t cap); +void ipc_message_add_data(ipc_message_t *msg, const char *value, size_t length); +void ipc_message_add_item(ipc_message_t *msg, l4_cap_idx_t cap); +void ipc_message_add_fpage(ipc_message_t *msg, l4_snd_fpage_t fpage); +void ipc_message_add_page(ipc_message_t *msg, l4_umword_t hot_spot, l4_fpage_t fpage); +void ipc_message_add_string(ipc_message_t *msg, const char *value); +void ipc_message_add_word(ipc_message_t *msg, l4_umword_t value); +void ipc_message_propagate_item(ipc_message_t *msg, l4_cap_idx_t cap); +void *ipc_message_reserve_data(ipc_message_t *msg, size_t length); +void *ipc_message_reserve_words(ipc_message_t *msg, size_t length); +void ipc_message_send_error(ipc_message_t *msg, long error); + +/* Access operations. */ + +l4_umword_t ipc_message_get_word(ipc_message_t *msg, unsigned int word); +l4_umword_t *ipc_message_get_word_address(ipc_message_t *msg, unsigned int word); +unsigned int ipc_message_number_of_items(ipc_message_t *msg); +unsigned int ipc_message_number_of_words(ipc_message_t *msg); + +/* Supporting operations. */ + +void ipc_message_discard_capability(ipc_message_t *msg, l4_cap_idx_t cap); +void ipc_message_discard_dataspace(ipc_message_t *msg, l4re_ds_t mem, l4_addr_t addr); +long ipc_message_expect_capabilities(ipc_message_t *msg, int number); +long ipc_message_expect_capability(ipc_message_t *msg, int item); +void ipc_message_export_capability(ipc_message_t *msg, int item, l4_cap_idx_t ref); +void ipc_message_export_fpage(ipc_message_t *msg, int item, l4_snd_fpage_t fpage); +void ipc_message_export_page(ipc_message_t *msg, int item, l4_umword_t hot_spot, l4_fpage_t fpage); +long ipc_message_import_capability(ipc_message_t *msg, int item, l4_cap_idx_t *ref); +long ipc_message_import_dataspace(ipc_message_t *msg, int item, l4re_ds_t *mem, l4_addr_t *addr); +long ipc_message_import_fpage(ipc_message_t *msg, int item, l4_snd_fpage_t *fpage); +void ipc_message_propagate_capability(ipc_message_t *msg, int item, l4_cap_idx_t ref); +l4_msgtag_t ipc_message_reply_tag(ipc_message_t *msg); +l4_msgtag_t ipc_message_request_tag(ipc_message_t *msg, int op); + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/include/ipc/semaphore.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/include/ipc/semaphore.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,31 @@ +/* + * Semaphore utilities. + * + * Copyright (C) 2021 Paul Boddie + * + * 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 + */ + +#pragma once + +#include + +EXTERN_C_BEGIN + +long ipc_semaphore_down(l4_cap_idx_t cap); +long ipc_semaphore_up(l4_cap_idx_t cap); + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/include/ipc/server.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/include/ipc/server.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,150 @@ +/* + * Server binding/registration. + * + * Copyright (C) 2018, 2019, 2020, 2021 Paul Boddie + * + * 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 + */ + +#pragma once + +#include + +#include + +EXTERN_C_BEGIN + +/* A convenience macro for invoking the server mainloop. */ + +#define ipc_server_loop_for(TYPE, POINTER) \ + ipc_server_loop(TYPE##_expected_items, (TYPE *) POINTER, \ + (ipc_server_handler_type) handle_##TYPE) + +/* A handler function type. */ + +typedef void (*ipc_server_handler_type)(ipc_message_t *, void *); + +/* A finaliser function type. */ + +struct ipc_server_config_type; + +typedef void (*ipc_server_finaliser_type)(struct ipc_server_config_type *); + +/* A server configuration type. */ + +typedef struct ipc_server_config_type +{ + /* Component object references. C++ objects may provide different references + for the handler (providing access to the exposed interface) and the + finaliser (providing access to a distinct control interface). */ + + void *handler_obj; + void *finaliser_obj; + + /* Expected capability item limit for incoming messages. */ + + int expected_items; + + /* Handler for incoming messages and finaliser upon deletion. */ + + ipc_server_handler_type handler; + ipc_server_finaliser_type finaliser; + + /* Create a new thread. */ + + int new_thread; + + /* Thread and IPC capabilities. */ + + l4_cap_idx_t thread; + l4_cap_idx_t server; + + /* Receive deletion notifications via an IRQ. */ + + int notifications; + l4_cap_idx_t irq; + +} ipc_server_config_type; + + + +/* Associate a notification IRQ with an IPC gate in the main thread. */ + +long ipc_server_apply_irq(l4_cap_idx_t cap, l4_cap_idx_t *irq); + +/* Associate a notification IRQ with an IPC gate in the given thread. */ + +long ipc_server_apply_irq_for_thread(l4_cap_idx_t cap, l4_cap_idx_t *irq, l4_cap_idx_t thread); + +/* Bind the main thread to a named IPC gate capability. */ + +long ipc_server_bind(const char *name, l4_umword_t id, l4_cap_idx_t *server); + +/* Create a new IPC gate for the main thread. */ + +long ipc_server_new(l4_cap_idx_t *cap, void *obj); + +/* Create a new IPC gate for the given thread. */ + +long ipc_server_new_for_thread(l4_cap_idx_t *cap, void *obj, l4_cap_idx_t thread); + +/* Create an IPC gate for the main thread. */ + +long ipc_server_new_gate(l4_cap_idx_t *ref, l4_umword_t id); + +/* Create an IPC gate for the indicated thread. */ + +long ipc_server_new_gate_for_thread(l4_cap_idx_t *ref, l4_cap_idx_t thread, l4_umword_t id); + + + +/* Handle incoming messages for a server. */ + +long ipc_server_loop(int expected_items, void *obj, + ipc_server_handler_type handler); + +/* Handle incoming messages and IRQ notifications for a server. */ + +long ipc_server_managed_loop(int expected_items, void *obj, l4_cap_idx_t irq, + ipc_server_handler_type handler); + +/* A pthread-compatible mainloop initiation function. */ + +void *ipc_server_start_mainloop(void *data); + +/* Wait for an incoming message via a dedicated IPC gate for a thread. */ + +l4_msgtag_t ipc_server_wait(l4_umword_t id); + + + +/* Finalise a server configuration. */ + +void ipc_server_finalise_config(ipc_server_config_type *config); + +/* Discard any thread created but not initiated. */ + +void ipc_server_discard_thread(ipc_server_config_type *config); + +/* Initialise a server configuration. */ + +void ipc_server_init_config(ipc_server_config_type *config); + +/* Initialise and start a server using the given configuration. */ + +long ipc_server_start_config(ipc_server_config_type *config); + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/include/ipc/thread.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/include/ipc/thread.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,35 @@ +/* + * Thread-related initialisation. + * + * Copyright (C) 2021 Paul Boddie + * + * 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 + */ + +#pragma once + +#include + +EXTERN_C_BEGIN + +long ipc_cap_alloc_init(void); +long ipc_mem_init(void); + +/* Principal thread-related initialisation function. */ + +long ipc_thread_init(void); + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/include/ipc/util_ipc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/include/ipc/util_ipc.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,53 @@ +/* + * Interprocess communication abstractions. + * + * Copyright (C) 2018, 2019, 2021 Paul Boddie + * + * 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 + */ + +#pragma once + +#include +#include +#include +#include + +#include + + + +EXTERN_C_BEGIN + +/* Supporting operations. */ + +long _expect_capabilities(l4_buf_regs_t *bregs, int number); +long _expect_capability(l4_buf_regs_t *bregs, int item); +void _export_capability(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_cap_idx_t ref); +void _export_fpage(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_snd_fpage_t fpage); +void _export_page(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_umword_t hot_spot, l4_fpage_t fpage); +void _free_expected_capabilities(l4_buf_regs_t *bregs, int number); +long _import_capability(l4_msgtag_t tag, l4_buf_regs_t *bregs, l4_msg_regs_t *mregs, int item, l4_cap_idx_t *ref); +long _import_dataspace(l4_msgtag_t tag, l4_buf_regs_t *bregs, l4_msg_regs_t *mregs, int item, l4re_ds_t *mem, l4_addr_t *addr); +long _import_fpage(l4_msgtag_t tag, l4_buf_regs_t *bregs, l4_msg_regs_t *mregs, int item, l4_snd_fpage_t *fpage); + +/* Convenience operations. */ + +l4_msgtag_t util_ipc_reply(l4_msgtag_t tag); +l4_msgtag_t util_ipc_request(l4_msgtag_t tag, l4_cap_idx_t endpoint); +l4_msgtag_t util_ipc_send(l4_msgtag_t tag, l4_cap_idx_t endpoint); + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/lib/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/lib/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,4 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../../.. + +include $(L4DIR)/mk/subdir.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/lib/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/lib/src/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,12 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../../.. + +TARGET = libipc.a libipc.so +PC_FILENAME = libipc +SRC_C = cap_alloc.c direct.c irq.c mem_ipc.c message.c semaphore.c server.c thread.c util_ipc.c +REQUIRES_LIBS = l4re_c-util + +PRIVATE_INCDIR += $(PKGDIR)/include/ipc +CONTRIB_INCDIR = libipc + +include $(L4DIR)/mk/lib.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/lib/src/cap_alloc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/lib/src/cap_alloc.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,89 @@ +/* + * Capability allocation and management. + * + * Copyright (C) 2019, 2021 Paul Boddie + * + * 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 + +#include "cap_alloc.h" +#include "semaphore.h" + + + +/* Semaphore used if threading has been initialised by ipc_cap_alloc_init. */ + +l4_cap_idx_t ipc_cap_alloc_semaphore = L4_INVALID_CAP; + + + +/* Reserve and return a capability index. */ + +l4_cap_idx_t ipc_cap_alloc() +{ + l4_cap_idx_t cap; + long err; + + /* Allocate a capability in the critical section, then return. */ + + err = ipc_semaphore_down(ipc_cap_alloc_semaphore); + if (err) + return L4_INVALID_CAP; + + cap = l4re_util_cap_alloc(); + + ipc_semaphore_up(ipc_cap_alloc_semaphore); + + return cap; +} + +/* Release a capability. */ + +int ipc_cap_free(l4_cap_idx_t cap) +{ + long err; + + err = ipc_semaphore_down(ipc_cap_alloc_semaphore); + if (err) + return 0; + + l4re_util_cap_free(cap); + + ipc_semaphore_up(ipc_cap_alloc_semaphore); + + return 1; +} + +/* Free the indicated capability and unmap it. */ + +int ipc_cap_free_um(l4_cap_idx_t cap) +{ + long err; + + err = ipc_semaphore_down(ipc_cap_alloc_semaphore); + if (err) + return 0; + + l4re_util_cap_free_um(cap); + + ipc_semaphore_up(ipc_cap_alloc_semaphore); + + return 1; +} + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/lib/src/direct.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/lib/src/direct.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,66 @@ +/* + * Interprocess communication abstractions. + * + * Copyright (C) 2018, 2019 Paul Boddie + * + * 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 + +#include "direct.h" +#include "util_ipc.h" + + + +/* Direct operations. */ + +/* Reserve the given number of slots from zero for incoming capabilities. */ + +long ipc_expect_capabilities(int number) +{ + return _expect_capabilities(l4_utcb_br(), number); +} + +/* Reserve a slot for an incoming capability. */ + +long ipc_expect_capability(int item) +{ + return _expect_capability(l4_utcb_br(), item); +} + +/* Export a capability at the given position in the message. */ + +void ipc_export_capability(l4_msgtag_t tag, int item, l4_cap_idx_t ref) +{ + _export_capability(tag, l4_utcb_mr(), item, ref); +} + +/* Import the capability at the given item position, updating the buffer + registers for future capabilities. */ + +long ipc_import_capability(l4_msgtag_t tag, int item, l4_cap_idx_t *ref) +{ + return _import_capability(tag, l4_utcb_br(), l4_utcb_mr(), item, ref); +} + +/* Import a dataspace, mapping it to an address, updating the buffer registers + for future capabilities. */ + +long ipc_import_dataspace(l4_msgtag_t tag, int item, l4re_ds_t *mem, l4_addr_t *addr) +{ + return _import_dataspace(tag, l4_utcb_br(), l4_utcb_mr(), item, mem, addr); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/lib/src/irq.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/lib/src/irq.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,73 @@ +/* + * Interrupt request handling. + * + * Copyright (C) 2018, 2019, 2021 Paul Boddie + * + * 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 +#include +#include +#include + +#include "cap_alloc.h" +#include "irq.h" + + + +/* IRQ operations. */ + +/* Create an interrupt request object. */ + +long ipc_create_irq(l4_cap_idx_t *irq) +{ + long err; + + *irq = ipc_cap_alloc(); + + if (l4_is_invalid_cap(*irq)) + return -L4_ENOENT; + + err = l4_error(l4_factory_create_irq(l4re_env()->factory, *irq)); + + if (err) + { + ipc_cap_free_um(*irq); + return err; + } + + return L4_EOK; +} + +/* Initialise an interrupt request object for subsequent notifications. */ + +l4_msgtag_t ipc_init_irq(l4_cap_idx_t irq) +{ + return l4_irq_unmask(irq); +} + +/* Prepare a thread to receive IRQ object notifications. */ + +long ipc_bind_irq(l4_cap_idx_t irq, l4_umword_t id, l4_cap_idx_t thread) +{ + long err = l4_error(l4_rcv_ep_bind_thread(irq, thread, id)); + + if (err) + return err; + + return L4_EOK; +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/lib/src/mem_ipc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/lib/src/mem_ipc.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,116 @@ +/* + * Memory sharing abstractions. + * + * Copyright (C) 2018, 2019, 2021 Paul Boddie + * + * 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 +#include +#include +#include + +#include "cap_alloc.h" +#include "mem_ipc.h" +#include "semaphore.h" + + + +/* Semaphore used if threading has been initialised by ipc_mem_init. */ + +l4_cap_idx_t ipc_mem_semaphore = L4_INVALID_CAP; + + + +/* Generic memory allocation. */ + +long ipc_allocate(unsigned long size, void **addr, l4re_ds_t *ds) +{ + /* Allocate a capability for the dataspace. */ + + *ds = ipc_cap_alloc(); + + if (l4_is_invalid_cap(*ds)) + return -L4_ENOENT; + + /* Allocate and attach the memory for the dataspace. */ + + if (ipc_new_dataspace(*ds, size, 0, 0)) + { + ipc_cap_free_um(*ds); + return -L4_ENOMEM; + } + + if (ipc_attach_dataspace(*ds, size, addr)) + { + ipc_cap_free_um(*ds); + return -L4_ENOMEM; + } + + return L4_EOK; +} + +/* Create a dataspace. Equivalent to l4re_ma_alloc_align. */ + +long ipc_new_dataspace(l4_cap_idx_t cap, l4_mword_t size, l4_umword_t flags, l4_umword_t align) +{ + return l4re_ma_alloc_align(size, cap, flags, align); +} + +/* Attach a dataspace region. Similar to l4re_rm_attach. */ + +long ipc_attach_dataspace(l4re_ds_t ds, unsigned long size, void **addr) +{ + long err; + + err = ipc_semaphore_down(ipc_mem_semaphore); + if (err) + return err; + + err = l4re_rm_attach(addr, size, L4RE_RM_SEARCH_ADDR, ds, 0, L4_PAGESHIFT); + + ipc_semaphore_up(ipc_mem_semaphore); + + return err; +} + +/* Detach a dataspace region. Equivalent to l4re_rm_detach_unmap. */ + +long ipc_detach_dataspace(void *addr) +{ + long err; + + err = ipc_semaphore_down(ipc_mem_semaphore); + if (err) + return err; + + err = l4re_rm_detach_unmap((l4_addr_t) addr, L4RE_THIS_TASK_CAP); + + ipc_semaphore_up(ipc_mem_semaphore); + + return err; +} + +/* Obtain a dataspace size. Equivalent to l4re_ds_size. */ + +long ipc_dataspace_size(l4_cap_idx_t cap, unsigned long *size) +{ + *size = l4re_ds_size(cap); + return L4_EOK; +} + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/lib/src/message.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/lib/src/message.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,485 @@ +/* + * Interprocess communication message abstraction. + * + * Copyright (C) 2018, 2019, 2021 Paul Boddie + * + * 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 + +#include "cap_alloc.h" +#include "message.h" +#include "mem_ipc.h" +#include "util_ipc.h" + + + +/* Calculate the given length rounded up to whole word increments. */ + +static size_t get_size_in_words(size_t length) +{ + size_t mask = sizeof(l4_umword_t) - 1; + return (length + mask) & ~mask; +} + + + +/* Message operations. */ + +/* Discard capabilities for transfer to other tasks. */ + +void ipc_message_discard(ipc_message_t *msg) +{ + unsigned int i; + + for (i = 0; i < msg->discarded_items; i++) + ipc_cap_free_um(msg->to_discard[i]); +} + +/* Initialise a message structure with the given number of expected items. */ + +long ipc_message_expect(ipc_message_t *msg, unsigned int expected_items) +{ + long err = ipc_message_expect_capabilities(msg, expected_items); + + if (err) + return err; + + /* Restore the buffer registers immediately. */ + + ipc_message_restore_buffer_registers(msg); + + return L4_EOK; +} + +/* Free capabilities expected in messages. */ + +void ipc_message_free(ipc_message_t *msg) +{ + _free_expected_capabilities(&msg->bregs, msg->expected_items); +} + +/* Clear message attributes for sending and response handling. */ + +void ipc_message_new(ipc_message_t *msg) +{ + /* Set a default for expected items. */ + + msg->expected_items = 0; + ipc_message_reset(msg); +} + +/* Open an incoming message by resetting sending state and preserving the + message registers plus the buffer registers for the expected number of + items. */ + +void ipc_message_open(ipc_message_t *msg) +{ + ipc_message_reset(msg); + ipc_message_preserve_buffer_registers(msg); + ipc_message_preserve_message_registers(msg); +} + +/* Preserve the buffer registers. */ + +void ipc_message_preserve_buffer_registers(ipc_message_t *msg) +{ + unsigned int i; + + /* Reference the UTCB virtual registers. */ + + l4_buf_regs_t *bregs = l4_utcb_br(); + + msg->bregs.bdr = bregs->bdr; + + for (i = 0; i < msg->expected_items; i++) + msg->bregs.br[i] = bregs->br[i]; +} + +/* Preserve the message registers. */ + +void ipc_message_preserve_message_registers(ipc_message_t *msg) +{ + /* Compute the number of message register words affected. */ + + unsigned int i, affected_words = l4_msgtag_words(msg->tag) + + 2 * l4_msgtag_items(msg->tag); + + /* Reference the UTCB virtual registers. */ + + l4_msg_regs_t *mregs = l4_utcb_mr(); + + /* Copy message register information. */ + + for (i = 0; i < affected_words; i++) + msg->mregs.mr[i] = mregs->mr[i]; +} + +/* Restore the message and buffer registers. */ + +void ipc_message_prepare(ipc_message_t *msg) +{ + ipc_message_restore_buffer_registers(msg); + ipc_message_restore_message_registers(msg); +} + +/* Restore buffer registers so that item expectations can be set. */ + +void ipc_message_restore_buffer_registers(ipc_message_t *msg) +{ + unsigned int i; + + /* Reference the UTCB virtual registers. */ + + l4_buf_regs_t *bregs = l4_utcb_br(); + + /* Restore buffer register information. */ + + bregs->bdr = msg->bregs.bdr; + + for (i = 0; i < msg->expected_items; i++) + bregs->br[i] = msg->bregs.br[i]; +} + +/* Restore message registers to communicate recorded data and items. */ + +void ipc_message_restore_message_registers(ipc_message_t *msg) +{ + /* Compute the number of message register words affected. */ + + unsigned int i, affected_words = msg->words + 2 * msg->items; + + /* Reference the UTCB virtual registers. */ + + l4_msg_regs_t *mregs = l4_utcb_mr(); + + /* Restore message register information. */ + + for (i = 0; i < affected_words; i++) + mregs->mr[i] = msg->mregs.mr[i]; +} + +/* Prepare and send a reply using the message. */ + +void ipc_message_reply(ipc_message_t *msg) +{ + ipc_message_prepare(msg); + msg->tag = util_ipc_reply(ipc_message_reply_tag(msg)); +} + +/* Prepare and send a request using the message, involving the given operation, + directed at the indicated endpoint. Open a message for the reply. */ + +void ipc_message_request(ipc_message_t *msg, int op, l4_cap_idx_t endpoint) +{ + ipc_message_prepare(msg); + msg->tag = util_ipc_request(ipc_message_request_tag(msg, op), endpoint); + ipc_message_open(msg); +} + +/* Prepare and send a message, involving the given operation, directed at the + indicated endpoint. No reply is expected. */ + +void ipc_message_send(ipc_message_t *msg, int op, l4_cap_idx_t endpoint) +{ + ipc_message_prepare(msg); + msg->tag = util_ipc_send(ipc_message_request_tag(msg, op), endpoint); +} + +/* Reset the state of the message for sending purposes. */ + +void ipc_message_reset(ipc_message_t *msg) +{ + /* Initialise words and items for sending. */ + + msg->discarded_items = 0; + msg->words = 0; + msg->items = 0; + + /* Message label overriding. */ + + msg->new_label = 0; + + /* Server control. */ + + msg->terminating = 0; +} + +/* Wait for an incoming message. */ + +void ipc_message_wait(ipc_message_t *msg, l4_umword_t *label) +{ + msg->tag = l4_ipc_wait(l4_utcb(), label, L4_IPC_NEVER); +} + + + +/* Add a capability to the message. */ + +void ipc_message_add_capability(ipc_message_t *msg, l4_cap_idx_t cap) +{ + ipc_message_export_capability(msg, msg->items++, cap); + if (cap & IPC_DISCARD_CAP_FLAG) + ipc_message_discard_capability(msg, cap & ~IPC_DISCARD_CAP_FLAG); +} + +/* Add an item to the message. */ + +void ipc_message_add_item(ipc_message_t *msg, l4_cap_idx_t cap) +{ + ipc_message_export_capability(msg, msg->items++, cap); + if (cap & IPC_DISCARD_CAP_FLAG) + ipc_message_discard_capability(msg, cap & ~IPC_DISCARD_CAP_FLAG); +} + +/* Add a flexpage to the message using a type to combine the "hot spot" and + flexpage. */ + +void ipc_message_add_fpage(ipc_message_t *msg, l4_snd_fpage_t fpage) +{ + ipc_message_export_fpage(msg, msg->items++, fpage); +} + +/* Add a flexpage to the message. */ + +void ipc_message_add_page(ipc_message_t *msg, l4_umword_t hot_spot, + l4_fpage_t fpage) +{ + ipc_message_export_page(msg, msg->items++, hot_spot, fpage); +} + +/* Add a word value to the message. */ + +void ipc_message_add_word(ipc_message_t *msg, l4_umword_t value) +{ + /* NOTE: Should raise an exception if there are items. */ + + if (!msg->items) + msg->mregs.mr[msg->words++] = value; +} + +/* Add the given dimensioned data to the message. */ + +void ipc_message_add_data(ipc_message_t *msg, const char *value, size_t length) +{ + void *target = ipc_message_reserve_data(msg, length); + + memcpy(target, value, length); +} + +/* Add the given null-terminated character string to the message. */ + +void ipc_message_add_string(ipc_message_t *msg, const char *value) +{ + ipc_message_add_data(msg, value, strlen(value) + 1); +} + +/* Propagate the given item to the message. */ + +void ipc_message_propagate_item(ipc_message_t *msg, l4_cap_idx_t cap) +{ + ipc_message_propagate_capability(msg, msg->items++, cap); +} + +/* Indicate an error condition in the message. */ + +void ipc_message_send_error(ipc_message_t *msg, long error) +{ + msg->new_label = error; +} + +/* Return a word value from the message. */ + +l4_umword_t ipc_message_get_word(ipc_message_t *msg, unsigned int word) +{ + return msg->mregs.mr[word]; +} + +/* Return a pointer to a word in the message. */ + +l4_umword_t *ipc_message_get_word_address(ipc_message_t *msg, unsigned int word) +{ + return &msg->mregs.mr[word]; +} + +/* Return the number of received items. */ + +unsigned int ipc_message_number_of_items(ipc_message_t *msg) +{ + return l4_msgtag_items(msg->tag); +} + +/* Return the number of received words. */ + +unsigned int ipc_message_number_of_words(ipc_message_t *msg) +{ + return l4_msgtag_words(msg->tag); +} + +/* Message tag generation. */ + +l4_msgtag_t ipc_message_reply_tag(ipc_message_t *msg) +{ + return l4_msgtag(msg->new_label, msg->words, msg->items, 0); +} + +l4_msgtag_t ipc_message_request_tag(ipc_message_t *msg, int op) +{ + return l4_msgtag(op, msg->words, msg->items, 0); +} + +/* Reserve space for dimensioned data, returning a pointer to use to add the + data. The length of the data is incorporated into the message. */ + +void *ipc_message_reserve_data(ipc_message_t *msg, size_t length) +{ + /* Indicate the length of the data. */ + + ipc_message_add_word(msg, length); + + /* Reserve the space. */ + + return ipc_message_reserve_words(msg, length); +} + +/* Reserve space for dimensioned data, returning a pointer to use to add the + data. The length is not incorporated into the message. */ + +void *ipc_message_reserve_words(ipc_message_t *msg, size_t length) +{ + /* Calculate the rounded-up size of the data and the necessary padding. */ + + size_t size = get_size_in_words(length); + size_t padding = size - length; + void *target; + + /* NOTE: Should test the length against the capacity of the message. */ + + /* Obtain the location of the next word, where the data will be copied. */ + + target = &msg->mregs.mr[msg->words]; + + /* Pad the data and update the number of words. */ + + memset(target + length, 0, padding); + msg->words += size / sizeof(l4_umword_t); + + return target; +} + + + +/* Discard a capability after replying. */ + +void ipc_message_discard_capability(ipc_message_t *msg, l4_cap_idx_t cap) +{ + msg->to_discard[msg->discarded_items++] = cap; +} + +/* Discard a dataspace. */ + +void ipc_message_discard_dataspace(ipc_message_t *msg, l4re_ds_t mem, l4_addr_t addr) +{ + ipc_message_discard_capability(msg, mem); + ipc_detach_dataspace((void *) addr); +} + +/* Reserve the given number slots from zero for incoming capabilities. */ + +long ipc_message_expect_capabilities(ipc_message_t *msg, int number) +{ + msg->expected_items = number; + return _expect_capabilities(&msg->bregs, number); +} + +/* Reserve a slot for an incoming capability. */ + +long ipc_message_expect_capability(ipc_message_t *msg, int item) +{ + if (item >= (int) msg->expected_items) + msg->expected_items = item + 1; + + return _expect_capability(&msg->bregs, item); +} + +/* Export a capability at the given position in the message. */ + +void ipc_message_export_capability(ipc_message_t *msg, int item, l4_cap_idx_t ref) +{ + msg->mregs.mr[msg->words + item * 2] = 0 | L4_ITEM_MAP; + msg->mregs.mr[msg->words + item * 2 + 1] = l4_obj_fpage(ref, 0, L4_FPAGE_RWX).raw; +} + +/* Export a flexpage at the given position in the message. Here, the snd_base + member of the flexpage structure is used to hold the "hot spot" value. */ + +void ipc_message_export_fpage(ipc_message_t *msg, int item, l4_snd_fpage_t fpage) +{ + msg->mregs.mr[msg->words + item * 2] = l4_map_control(fpage.snd_base, L4_FPAGE_CACHEABLE, 0); + msg->mregs.mr[msg->words + item * 2 + 1] = fpage.fpage.raw; +} + +/* Export a flexpage at the given position in the message. */ + +void ipc_message_export_page(ipc_message_t *msg, int item, l4_umword_t hot_spot, l4_fpage_t fpage) +{ + msg->mregs.mr[msg->words + item * 2] = l4_map_control(hot_spot, L4_FPAGE_CACHEABLE, 0); + msg->mregs.mr[msg->words + item * 2 + 1] = fpage.raw; +} + +/* Import from the message the capability at the given item position, updating + the buffer registers for future capabilities. */ + +long ipc_message_import_capability(ipc_message_t *msg, int item, l4_cap_idx_t *ref) +{ + long err; + + err = _import_capability(msg->tag, &msg->bregs, &msg->mregs, item, ref); + if (err) + return err; + + return ipc_message_expect_capability(msg, item); +} + +/* Import from the message a dataspace, mapping it to an address, updating the + buffer registers for future capabilities. */ + +long ipc_message_import_dataspace(ipc_message_t *msg, int item, l4re_ds_t *mem, l4_addr_t *addr) +{ + long err; + + err = _import_dataspace(msg->tag, &msg->bregs, &msg->mregs, item, mem, addr); + if (err) + return err; + + return ipc_message_expect_capability(msg, item); +} + +/* Import from the message the flexpage at the given item position. */ + +long ipc_message_import_fpage(ipc_message_t *msg, int item, l4_snd_fpage_t *fpage) +{ + return _import_fpage(msg->tag, &msg->bregs, &msg->mregs, item, fpage); +} + +/* Export a capability, discarding it by propagating it to the recipient. */ + +void ipc_message_propagate_capability(ipc_message_t *msg, int item, l4_cap_idx_t ref) +{ + ipc_message_export_capability(msg, item, ref); + ipc_message_discard_capability(msg, ref); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/lib/src/semaphore.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/lib/src/semaphore.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,91 @@ +/* + * Semaphore utilities. + * + * Copyright (C) 2021 Paul Boddie + * + * 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 +#include + +#include "semaphore.h" + + + +/* Obtain control of a semaphore. */ + +long ipc_semaphore_down(l4_cap_idx_t semaphore) +{ + long err; + + if (l4_is_valid_cap(semaphore)) + { + do + { + /* Since l4_irq_trigger is a "send-only" operation, l4_error is not + appropriate. */ + + err = l4_ipc_error(l4_semaphore_down(semaphore, L4_IPC_NEVER), l4_utcb()); + + /* Handle EAGAIN ("Resource temporarily unavailable") by just retrying. */ + + if (err) + { + if (err == -L4_EAGAIN) + continue; + else + return err; + } + } + while (0); + } + + return L4_EOK; +} + +/* Relinquish control of a semaphore. */ + +long ipc_semaphore_up(l4_cap_idx_t semaphore) +{ + long err; + + if (l4_is_valid_cap(semaphore)) + { + do + { + /* Since l4_irq_trigger is a "send-only" operation, l4_error is not + appropriate. */ + + err = l4_ipc_error(l4_semaphore_up(semaphore), l4_utcb()); + + /* Handle EAGAIN ("Resource temporarily unavailable") by just retrying. */ + + if (err) + { + if (err == -L4_EAGAIN) + continue; + else + return err; + } + } + while (0); + } + + return L4_EOK; +} + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/lib/src/server.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/lib/src/server.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,343 @@ +/* + * Server binding/registration. + * + * Copyright (C) 2018, 2019, 2020, 2021 Paul Boddie + * + * 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 +#include +#include +#include +#include +#include + +#include + +#include "cap_alloc.h" +#include "irq.h" +#include "server.h" + + + +/* Associate an IRQ with the IPC gate in the main thread to handle gate deletion + notifications. */ + +long ipc_server_apply_irq(l4_cap_idx_t cap, l4_cap_idx_t *irq) +{ + return ipc_server_apply_irq_for_thread(cap, irq, l4re_env()->main_thread); +} + +/* Associate an IRQ with the IPC gate in the given thread to handle gate deletion + notifications. */ + +long ipc_server_apply_irq_for_thread(l4_cap_idx_t cap, l4_cap_idx_t *irq, l4_cap_idx_t thread) +{ + /* Create an IRQ for the gate. */ + + long err = ipc_create_irq(irq); + + if (err) + return err; + + /* Bind the IRQ to the thread, presenting the label if it provides the + incoming message. */ + + err = l4_error(l4_rcv_ep_bind_thread(*irq, thread, (l4_umword_t) *irq)); + + if (err) + { + ipc_cap_free_um(*irq); + return err; + } + + /* Register for notifications. The thread associated with the gate seems to be + needed. */ + + err = l4_error(l4_thread_register_del_irq(thread, *irq)); + + if (err) + { + ipc_cap_free_um(*irq); + return err; + } + + /* Decrease the reference count on the server capability (IPC gate). */ + + return l4_error(l4_kobject_dec_refcnt(cap, 1)); +} + + + +/* Bind the main thread to the named capability, employing an identifier for + the IPC gate and returning the capability index. */ + +long ipc_server_bind(const char *name, l4_umword_t id, l4_cap_idx_t *server) +{ + /* Obtain a reference to the device. */ + + *server = l4re_env_get_cap(name); + + if (l4_is_invalid_cap(*server)) + return -L4_ENOENT; + + /* Bind to an IPC gate with the label identifying the server as message + destination. */ + + return l4_error(l4_rcv_ep_bind_thread(*server, l4re_env()->main_thread, id)); +} + +/* Initialise a new server capability, binding it to the main thread. */ + +long ipc_server_new(l4_cap_idx_t *cap, void *obj) +{ + return ipc_server_new_for_thread(cap, obj, l4re_env()->main_thread); +} + +/* Initialise a new server capability, binding it to the given thread. */ + +long ipc_server_new_for_thread(l4_cap_idx_t *cap, void *obj, l4_cap_idx_t thread) +{ + l4_umword_t label = (l4_umword_t) obj; + + /* Create an IPC gate, presenting the resource's label if this gate provides + the message. */ + + return ipc_server_new_gate_for_thread(cap, thread, label); +} + +/* Create an IPC gate, exporting via a new capability an object with the given + identifier. */ + +long ipc_server_new_gate(l4_cap_idx_t *ref, l4_umword_t id) +{ + return ipc_server_new_gate_for_thread(ref, l4re_env()->main_thread, id); +} + +/* Create an IPC gate associated with a specific thread. */ + +long ipc_server_new_gate_for_thread(l4_cap_idx_t *ref, l4_cap_idx_t thread, l4_umword_t id) +{ + long err; + + *ref = ipc_cap_alloc(); + + if (l4_is_invalid_cap(*ref)) + return -L4_ENOENT; + + /* Associate the object with an IPC gate. */ + + err = l4_error(l4_factory_create_gate(l4re_env()->factory, *ref, thread, id)); + + if (err) + ipc_cap_free_um(*ref); + + return err; +} + + + +/* A server main loop with no endpoint deletion detection. */ + +long ipc_server_loop(int expected_items, void *obj, + ipc_server_handler_type handler) +{ + return ipc_server_managed_loop(expected_items, obj, L4_INVALID_CAP, handler); +} + +/* A server main loop handling endpoint deletion for an IPC gate dedicated to + a particular object within its own thread. */ + +long ipc_server_managed_loop(int expected_items, void *obj, l4_cap_idx_t irq, + ipc_server_handler_type handler) +{ + ipc_message_t msg; + l4_umword_t label, irq_label = (l4_umword_t) irq; + + /* Declare the extent to which capabilities are expected in messages. */ + + long err = ipc_message_expect(&msg, expected_items); + + if (err) + return err; + + /* Unmask the interrupt. */ + + if (l4_is_valid_cap(irq)) + ipc_init_irq(irq); + + /* Wait for an incoming message. */ + + while (1) + { + ipc_message_wait(&msg, &label); + + /* Clear lower label bits. */ + + label = label & ~3UL; + + /* Ignore erroneous messages. */ + + if (l4_ipc_error(msg.tag, l4_utcb())) + continue; + + /* Message involves the IPC gate itself. */ + + if (label != irq_label) + handler(&msg, obj); + + /* Message involves the IRQ or a termination condition occurred. */ + + if ((label == irq_label) || msg.terminating) + break; + } + + /* Free expected capabilities. */ + + ipc_message_free(&msg); + + return L4_EOK; +} + +/* A pthread-compatible mainloop initiation function. */ + +void *ipc_server_start_mainloop(void *data) +{ + ipc_server_config_type *config = (ipc_server_config_type *) data; + + long err = ipc_server_managed_loop(config->expected_items, config->handler_obj, + config->irq, config->handler); + + if (config->finaliser != NULL) + config->finaliser(config); + + return (void *) err; +} + +/* Wait for an incoming message via an IPC gate dedicated to a particular + object within its own thread. */ + +l4_msgtag_t ipc_server_wait(l4_umword_t id) +{ + l4_umword_t label; + l4_msgtag_t tag; + + /* Ignore errors and messages not intended for the identified gate. */ + + do tag = l4_ipc_wait(l4_utcb(), &label, L4_IPC_NEVER); + while (l4_ipc_error(tag, l4_utcb()) || (label & ~3UL) != id); + + return tag; +} + + + +/* Finalise a server configuration. */ + +void ipc_server_finalise_config(ipc_server_config_type *config) +{ + if (l4_is_valid_cap(config->server)) + { + ipc_cap_free_um(config->server); + config->server = L4_INVALID_CAP; + } + + if (l4_is_valid_cap(config->irq)) + { + ipc_cap_free_um(config->irq); + config->irq = L4_INVALID_CAP; + } +} + +/* Discard any thread created but not initiated. */ + +void ipc_server_discard_thread(ipc_server_config_type *config) +{ + if (config->new_thread && l4_is_valid_cap(config->thread)) + { + ipc_cap_free_um(config->thread); + config->thread = L4_INVALID_CAP; + } +} + +/* Initialise a server configuration. */ + +void ipc_server_init_config(ipc_server_config_type *config) +{ + /* No object references defined. */ + + config->handler_obj = NULL; + config->finaliser_obj = NULL; + + /* Expect no capability items by default. */ + + config->expected_items = 0; + + /* No handler or finaliser defined. */ + + config->handler = NULL; + config->finaliser = NULL; + + /* No new thread for the mainloop. */ + + config->new_thread = 0; + + /* Main thread by default with IPC gate to be allocated. */ + + config->thread = l4re_env()->main_thread; + config->server = L4_INVALID_CAP; + + /* No notifications and with IRQ to be potentially allocated. */ + + config->notifications = 0; + config->irq = L4_INVALID_CAP; +} + +/* Initialise and start a server using the given configuration. */ + +long ipc_server_start_config(ipc_server_config_type *config) +{ + long err; + + /* Allocate a new IPC gate if one is not already defined. */ + + if (l4_is_invalid_cap(config->server)) + { + err = ipc_server_new_for_thread(&config->server, config->handler_obj, config->thread); + + if (err) + return err; + } + + /* Allocate an IRQ for notifications if requested. */ + + if (config->notifications) + { + err = ipc_server_apply_irq_for_thread(config->server, &config->irq, config->thread); + + if (err) + return err; + } + + /* With a new thread, return the last status value. Otherwise, invoke the main + loop. */ + + if (config->new_thread) + return L4_EOK; + else + return (long) ipc_server_start_mainloop(config); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/lib/src/thread.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/lib/src/thread.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,87 @@ +/* + * Thread-related initialisation activities. + * + * Copyright (C) 2021 Paul Boddie + * + * 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 +#include +#include +#include + +#include "cap_alloc.h" +#include "semaphore.h" +#include "thread.h" + + + +/* Bootstrap the semaphore support needed by the allocation function. */ + +static long ipc_semaphore_init(l4_cap_idx_t *semaphore) +{ + if (l4_is_invalid_cap(*semaphore)) + { + *semaphore = l4re_util_cap_alloc(); + + if (l4_is_invalid_cap(*semaphore)) + return -L4_ENOENT; + + if (l4_error(l4_factory_create(l4re_env()->factory, L4_PROTO_SEMAPHORE, *semaphore))) + { + ipc_cap_free_um(*semaphore); + return -L4_ENOENT; + } + + return ipc_semaphore_up(*semaphore); + } + else + return L4_EOK; +} + +/* Bootstrap the semaphore support needed by the allocation functions. */ + +extern l4_cap_idx_t ipc_cap_alloc_semaphore; + +long ipc_cap_alloc_init() +{ + return ipc_semaphore_init(&ipc_cap_alloc_semaphore); +} + +/* Bootstrap the semaphore support needed by the memory functions. */ + +extern l4_cap_idx_t ipc_mem_semaphore; + +long ipc_mem_init() +{ + return ipc_semaphore_init(&ipc_mem_semaphore); +} + +/* General semaphore initialisation. */ + +long ipc_thread_init() +{ + long err; + + err = ipc_cap_alloc_init(); + if (err) + return err; + + return ipc_mem_init(); +} + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 40dc1cbd5356 -r 49d8e9637cdb libipc/lib/src/util_ipc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/lib/src/util_ipc.c Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,224 @@ +/* + * Interprocess communication abstractions. + * + * Copyright (C) 2018, 2019, 2021 Paul Boddie + * + * 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 +#include +#include +#include + +#include "cap_alloc.h" +#include "mem_ipc.h" +#include "util_ipc.h" + + + +/* Declare expected capabilities. */ + +long _expect_capabilities(l4_buf_regs_t *bregs, int number) +{ + int i; + long err; + + for (i = 0; i < number; i++) + { + err = _expect_capability(bregs, i); + if (err) + return err; + } + + return L4_EOK; +} + +/* Indicate that a capability is expected at the given position. */ + +long _expect_capability(l4_buf_regs_t *bregs, int item) +{ + l4_cap_idx_t future = ipc_cap_alloc(); + + if (l4_is_invalid_cap(future)) + return -L4_ENOENT; + + /* Indicate the expectation of a capability in return. */ + + bregs->bdr = 0; + bregs->br[item] = L4_RCV_ITEM_SINGLE_CAP | future; + + return L4_EOK; +} + +/* Export in the message at the given position the given capability. */ + +void _export_capability(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_cap_idx_t ref) +{ + int words = l4_msgtag_words(tag); + + mregs->mr[words + item * 2] = 0 | L4_ITEM_MAP; + mregs->mr[words + item * 2 + 1] = l4_obj_fpage(ref, 0, L4_FPAGE_RWX).raw; +} + +/* Export a flexpage at the given position in the message. Here, the snd_base + member of the flexpage structure is used to hold the "hot spot" value. */ + +void _export_fpage(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_snd_fpage_t fpage) +{ + int words = l4_msgtag_words(tag); + + mregs->mr[words + item * 2] = l4_map_control(fpage.snd_base, L4_FPAGE_CACHEABLE, 0); + mregs->mr[words + item * 2 + 1] = fpage.fpage.raw; +} + +/* Export a flexpage at the given position in the message. */ + +void _export_page(l4_msgtag_t tag, l4_msg_regs_t *mregs, int item, l4_umword_t hot_spot, l4_fpage_t fpage) +{ + int words = l4_msgtag_words(tag); + + mregs->mr[words + item * 2] = l4_map_control(hot_spot, L4_FPAGE_CACHEABLE, 0); + mregs->mr[words + item * 2 + 1] = fpage.raw; +} + +/* Free expected capabilities held by the buffer registers. */ + +void _free_expected_capabilities(l4_buf_regs_t *bregs, int number) +{ + int i; + l4_cap_idx_t cap; + + for (i = 0; i < number; i++) + { + cap = bregs->br[i] & L4_CAP_MASK; + if (l4_is_valid_cap(cap)) + ipc_cap_free_um(cap); + } +} + +/* Import from the message the capability at the given item position. */ + +long _import_capability(l4_msgtag_t tag, l4_buf_regs_t *bregs, + l4_msg_regs_t *mregs, int item, l4_cap_idx_t *ref) +{ + l4_snd_fpage_t fpage; + long err = _import_fpage(tag, bregs, mregs, item, &fpage); + + if (err) + return err; + + /* Check for a received capability. */ + + if ((fpage.snd_base & 0x3e) != 0x38) + return -L4_EIO; + + /* Update the supplied capability index. */ + + *ref = bregs->br[item] & L4_CAP_MASK; + + return L4_EOK; +} + +/* Import from the message a dataspace, mapping it to an address. */ + +long _import_dataspace(l4_msgtag_t tag, l4_buf_regs_t *bregs, + l4_msg_regs_t *mregs, int item, l4re_ds_t *mem, + l4_addr_t *addr) +{ + long err; + unsigned long size; + + *mem = ipc_cap_alloc(); + + err = _import_capability(tag, bregs, mregs, item, mem); + + if (err) + { + ipc_cap_free_um(*mem); + return err; + } + + /* Attach the dataspace to a region. */ + + err = ipc_dataspace_size(*mem, &size); + if (err) + { + ipc_cap_free_um(*mem); + return err; + } + + err = ipc_attach_dataspace(*mem, size, (void **) addr); + if (err) + { + ipc_cap_free_um(*mem); + return err; + } + + return L4_EOK; +} + +/* Import from the message the flexpage at the given item position. */ + +long _import_fpage(l4_msgtag_t tag, l4_buf_regs_t *bregs, + l4_msg_regs_t *mregs, int item, l4_snd_fpage_t *fpage) +{ + int words = l4_msgtag_words(tag); + + /* NOTE: Currently, this function does not interact with the received items, + but instead just returns the flexpage details from the message + words. */ + + (void) bregs; + + /* Obtain the item details for the capability. */ + + if (item >= (int) l4_msgtag_items(tag)) + return -L4_EIO; + + /* Received items should start at zero. */ + + fpage->snd_base = mregs->mr[words + item * 2]; + fpage->fpage.raw = mregs->mr[words + item * 2 + 1]; + + return L4_EOK; +} + + + +/* Convenience operations. */ + +/* Send a reply to a call using the given message tag. */ + +l4_msgtag_t util_ipc_reply(l4_msgtag_t tag) +{ + return l4_ipc_send(L4_INVALID_CAP | L4_SYSF_REPLY, l4_utcb(), tag, L4_IPC_NEVER); +} + +/* Send a request using a call with the given message tag to the indicated + endpoint. */ + +l4_msgtag_t util_ipc_request(l4_msgtag_t tag, l4_cap_idx_t endpoint) +{ + return l4_ipc_call(endpoint, l4_utcb(), tag, L4_IPC_NEVER); +} + +/* Send data with the given message tag to the indicated endpoint. */ + +l4_msgtag_t util_ipc_send(l4_msgtag_t tag, l4_cap_idx_t endpoint) +{ + return l4_ipc_send(endpoint, l4_utcb(), tag, L4_IPC_NEVER); +} diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/Control --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/Control Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,2 @@ +provides: libsystypes +maintainer: paul@boddie.org.uk diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,4 @@ +PKGDIR ?= . +L4DIR ?= $(PKGDIR)/../../.. + +include $(L4DIR)/mk/subdir.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/docs/COPYING-GPL-2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/docs/COPYING-GPL-2 Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,1 @@ +LICENCE.txt \ No newline at end of file diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/docs/COPYING.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/docs/COPYING.txt Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,22 @@ +Licence Agreement +----------------- + +All original work in this distribution is covered by the following copyright +and licensing information: + +Copyright (C) 2019 Paul Boddie + +This software 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 software 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 library; see the file LICENCE.txt +If not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/docs/LICENCE.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/docs/LICENCE.txt Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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 + + 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) + + 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. + +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) year 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 Lesser General +Public License instead of this License. diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/idl/dataspace.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/dataspace.idl Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,44 @@ +#include /* L4RE_PROTO_DATASPACE */ +#include /* address_t, offset_t */ + +/* A dataspace interface. */ + +[protocol(L4RE_PROTO_DATASPACE)] +interface Dataspace +{ + /* Map memory within a dataspace. */ + + [opcode(0)] void map(in offset_t offset, in address_t hot_spot, + in map_flags_t flags, out fpage region); + + /* Clear a dataspace. */ + + [opcode(1)] void clear(in address_t offset, in offset_t size); + + /* Obtain statistics about a dataspace. */ + + [opcode(2)] void info(out offset_t size, out map_flags_t flags); + + /* Copy data between dataspaces. */ + + [opcode(3)] void copy_in(in address_t dest_offset, in cap source, + in address_t source_offset, in offset_t size); + + /* Deprecated: take a reference to a dataspace. */ + + [opcode(4)] void take(); + + /* Deprecated: release a reference to a dataspace. */ + + [opcode(5)] void release(); + + /* Obtain the physical address of the given offset in a dataspace, along with + the largest physically contiguous region at or after the address in the + dataspace. */ + + [opcode(6)] void phys(in address_t offset, out address_t address, out l4_size_t size); + + /* Allocate at least the given size at the given address in a dataspace. */ + + [opcode(7)] void allocate(in address_t offset, in l4_size_t size); +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/idl/dataspace_factory.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/dataspace_factory.idl Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,15 @@ +#include +#include /* L4RE_PROTO_DATASPACE */ + +/* Dataspace operations exposed via the factory interface. This appears to + involve extra tag values which are incorporated into the provided values.*/ + +[protocol(L4_PROTO_FACTORY)] +interface DataspaceFactory +{ + /* Create a new dataspace. */ + + [opcode(L4RE_PROTO_DATASPACE)] + void alloc(in ipc_varg_long_t size, in ipc_varg_unsigned_long_t flags, + in ipc_varg_unsigned_long_t align, out cap ds); +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/idl/file.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/file.idl Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,15 @@ +#include /* offset_t */ + +/* An interface providing operations common to both unmapped and mapped files. + Other interfaces are used to specialise different kinds of files. */ + +interface File +{ + /* Obtain a file metadata object. */ + + [opcode(11)] void fstat(out offset_t size, out cap statcap); + + /* Resize the file. */ + + [opcode(21)] void resize(inout offset_t size); +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/idl/filesystem.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/filesystem.idl Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,10 @@ +#include /* user_t */ + +/* An interface providing filesystem operations. */ + +interface Filesystem +{ + /* Obtain filesystem access for the given user details. */ + + [opcode(6)] void open_for_user(in user_t user, out cap opener); +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/idl/filesystem_factory.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/filesystem_factory.idl Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,15 @@ +#include /* sys_uid_t, sys_gid_t, sys_mode_t */ + +/* Filesystem operations exposed via the factory interface. This appears to + involve extra tag values which are incorporated into the provided values. */ + +[protocol(L4_PROTO_FACTORY)] +interface FilesystemFactory +{ + /* Obtain filesystem access for the given user details. */ + + [opcode(6)] void open_for_user(in ipc_varg_sys_uid_t uid, + in ipc_varg_sys_gid_t gid, + in ipc_varg_sys_mode_t umask, + out cap opener); +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/idl/flush.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/flush.idl Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,10 @@ +#include /* offset_t */ + +/* An interface providing a flush operation for files and pipes. */ + +interface Flush +{ + /* Flush data and update the size, if appropriate. */ + + [opcode(5)] void flush(in offset_t populated_size, out offset_t size); +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/idl/mapped_file.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/mapped_file.idl Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,13 @@ +#include /* offset_t */ + +/* An interface providing operations specific to mapped files. */ + +interface MappedFile +{ + /* Memory-map a file for the given file position and length, obtaining the + limits of the mapped region and the size of the file. */ + + [opcode(7)] void mmap(in offset_t position, in offset_t length, + out offset_t start_pos, out offset_t end_pos, + out offset_t size); +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/idl/notification.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/notification.idl Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,12 @@ +#include /* notify_flags_t */ + +interface Notification +{ + /* Subscribe to events. */ + + [opcode(23)] void subscribe(in cap notifier, in notify_flags_t flags); + + /* Unsubscribe from events. */ + + [opcode(24)] void unsubscribe(in cap notifier); +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/idl/notifier.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/notifier.idl Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,8 @@ +#include /* notify_flags_t */ + +interface Notifier +{ + /* Send notification events. */ + + [opcode(25)] void notify(in notify_flags_t flags); +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/idl/opener.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/opener.idl Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,10 @@ +#include /* size_t */ + +/* An interface providing a way of opening filesystem objects. */ + +interface Opener +{ + /* Obtain an opener context for subsequent open operations. */ + + [opcode(13)] void context(out cap context); +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/idl/opener_context.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/opener_context.idl Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,24 @@ +#include /* flags_t, object_flags_t, offset_t */ + +/* An interface providing a way of opening filesystem objects relying on a + dataspace to transfer filesystem paths. */ + +interface OpenerContext +{ + /* Mount the filesystem reference given a mountpoint path written to the + dataspace. */ + + [opcode(0)] void mount(in cap fs); + + /* Obtain a filesystem reference. */ + + [opcode(1)] void getfs(out cap fs); + + /* Obtain a file reference given a path written to the context's dataspace. */ + + [opcode(12)] void open(in flags_t flags, out offset_t size, out cap file, + out object_flags_t object_flags); +}; + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/idl/pipe.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/pipe.idl Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,19 @@ +#include /* offset_t */ + +/* A pipe interface providing access to shared memory. */ + +interface Pipe +{ + /* Obtain details of the current region of shared memory. */ + + [opcode(16)] void current_region(out offset_t populated_size, out offset_t size); + + /* Advance to the next region of shared memory, indicating and obtaining the + populated limit of the region and obtaining the region size. */ + + [opcode(17)] void next_region(inout offset_t populated_size, out offset_t size); + + /* Return whether the pipe is closed or partly closed. */ + + [opcode(22)] void closed(out int closed); +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/idl/pipe_opener.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/pipe_opener.idl Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,11 @@ +#include /* offset_t */ + +/* An interface providing pipe-opening support. */ + +interface PipeOpener +{ + /* Obtain a pipe for communication between two endpoints, indicating a region + size for each section of a pipe. */ + + [opcode(20)] void pipe(in offset_t size, out cap reader, out cap writer); +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/idl/region_mapper.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/region_mapper.idl Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,46 @@ +#include /* L4RE_PROTO_RM */ +#include /* address_t, offset_t */ + +/* A region mapper/manager interface. */ + +[protocol(L4RE_PROTO_RM)] +interface RegionMapper +{ + /* Attach the memory associated with a dataspace, employing the given start + address to search for a suitable address for the region. */ + + [opcode(0)] void attach(inout address_t start, in offset_t size, + in map_flags_t flags, in cap ds, + in address_t offset, in unsigned char align); + + /* Detach memory from the task, searching from the given address for a region + of the given size. Return the start address, region size and dataspace. */ + + [opcode(1)] void detach(in address_t addr, in offset_t size, + in map_flags_t flags, out address_t start, + out offset_t rsize, out cap ds); + + /* Find a region starting from the given address and having the given size. + Return the start address, region size and dataspace. */ + + [opcode(2)] void find(inout address_t addr, inout offset_t size, + out map_flags_t flags, out address_t offset, + out cap ds); + + /* Reserve an area in the region map. */ + + [opcode(3)] void reserve_area(inout address_t start, in offset_t size, + in map_flags_t flags, in unsigned char align); + + /* Free (or unreserve) an area in the region map. */ + + [opcode(4)] void free_area(in address_t addr); + + /* Currently not fully supported by the interface generator... + + [opcode(5)] void get_regions(in address_t start, out Region[] regions); + + [opcode(6)] void get_areas(in address_t start, out Area[] areas); + + See pkg/l4re-core/l4re/include/rm for the Region and Area structures. */ +}; diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/include/Makefile Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,10 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../../.. + +PC_FILENAME = libsystypes +CONTRIB_INCDIR = libsystypes + +PKGNAME = libsystypes +CONTRIB_HEADERS = 1 + +include $(L4DIR)/mk/include.mk diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/include/systypes/base.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/include/systypes/base.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,96 @@ +/* + * Base types used by various other types. + * + * Copyright (C) 2019, 2021 Paul Boddie + * + * 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 + */ + +#pragma once + +#include + +#include + +EXTERN_C_BEGIN + +/* unsigned long is a 64-bit type. + See: pkg/l4re-core/l4sys/include/l4int.h */ + +/* Types for file access (access flags, offsets) and IPC operations. */ + +typedef unsigned long flags_t; +typedef unsigned long offset_t; +typedef l4_addr_t address_t; /* unsigned long */ + +/* Dataspace mapping flags. + See: pkg/l4re-core/l4re_c/include/dataspace.h */ + +typedef unsigned long map_flags_t; /* 64-bit */ + +/* Types and values for notification. */ + +typedef unsigned long notify_flags_t; + +enum notify_flags +{ + NOTIFY_CONTENT_AVAILABLE = 1, + NOTIFY_SPACE_AVAILABLE = 2, + NOTIFY_PEER_CLOSED = 4 +}; + +/* Filesystem object properties. */ + +typedef unsigned long object_flags_t; + +enum object_flags +{ + OBJECT_SUPPORTS_MMAP = 1, + OBJECT_HAS_SIZE = 2 +}; + +/* Equivalent types are defined in sys/types.h typically. In newlib, they are + defined in sys/_types.h if not defined elsewhere (such as in + machine/_types.h). */ + +typedef unsigned long long sys_dev_t; /* device number */ +typedef unsigned long sys_ino_t; /* inode number */ +typedef unsigned int sys_mode_t; /* file permissions */ +typedef unsigned int sys_nlink_t; /* link count */ +typedef unsigned int sys_uid_t; /* user identifier */ +typedef unsigned int sys_gid_t; /* group identifier */ +typedef long sys_off_t; /* file offset/position */ +typedef long sys_blksize_t; /* input/output block size */ +typedef long sys_blkcnt_t; /* number of 512-byte blocks */ + +/* Factory types for L4 factory interface invocations. */ + +ipc_varg_typedef(sys_mode_t, ipc_varg_sys_mode_t) +ipc_varg_typedef(sys_uid_t, ipc_varg_sys_uid_t) +ipc_varg_typedef(sys_gid_t, ipc_varg_sys_gid_t) + +#define ipc_varg_sys_mode(value) \ +ipc_varg_umword(ipc_varg_sys_mode_t, value) + +#define ipc_varg_sys_uid(value) \ +ipc_varg_umword(ipc_varg_sys_uid_t, value) + +#define ipc_varg_sys_gid(value) \ +ipc_varg_umword(ipc_varg_sys_gid_t, value) + +EXTERN_C_END + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/include/systypes/factory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/include/systypes/factory.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,56 @@ +/* + * Factory-related data type macros. + * + * Copyright (C) 2019 Paul Boddie + * + * 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 + */ + +#pragma once + +#include + + + +EXTERN_C_BEGIN + +/* Type and value constructor macros. */ + +#define ipc_varg_typedef(value_type, type) \ +typedef struct { l4_umword_t tag; value_type value; } type; + +#define ipc_varg_mword(type, value) \ +((type) {L4_VARG_TYPE_MWORD | (sizeof(l4_mword_t) << 16), value}) + +#define ipc_varg_umword(type, value) \ +((type) {L4_VARG_TYPE_UMWORD | (sizeof(l4_umword_t) << 16), value}) + +/* Tag inspection macros. */ + +#define ipc_varg_size(tag) (tag >> 16) + +#define ipc_varg_type(tag) (tag & 0xff) + +#define ipc_varg_word(tag) \ +((ipc_varg_type(tag) == L4_VARG_TYPE_MWORD) || \ + (ipc_varg_type(tag) == L4_VARG_TYPE_UMWORD)) + +/* Convenience macro for creating a type name, not necessarily employed by all + types. */ + +#define ipc_varg(type) ipc_varg_##type##_t + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/include/systypes/fcntl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/include/systypes/fcntl.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,49 @@ +/* + * File control definitions. + * + * Copyright (C) 2019, 2020 Paul Boddie + * + * 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 + */ + +#pragma once + +#include + +EXTERN_C_BEGIN + +/* Employ definitions compatible with fcntl-linux.h which can be different from + fcntl.h on MIPS and from Newlib. */ + +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_APPEND 0x0008 +#define O_CREAT 0x0200 +#define O_TRUNC 0x0400 +#define O_EXCL 0x0800 +#define O_NBIO 0x1000 +#define O_SYNC 0x2000 +#define O_NONBLOCK 0x4000 +#define O_NDELAY O_NONBLOCK +#define O_NOCTTY 0x8000 +#define O_DIRECTORY 0x200000 + +/* System-level functions. */ + +int open(const char *pathname, int flags, ... /* mode_t mode */); + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/include/systypes/stat.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/include/systypes/stat.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,49 @@ +/* + * File metadata abstractions. + * + * Copyright (C) 2019 Paul Boddie + * + * 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 + */ + +#pragma once + +#include +#include + +EXTERN_C_BEGIN + +/* File metadata abstraction. */ + +typedef struct +{ + sys_dev_t st_dev; + sys_ino_t st_ino; + sys_mode_t st_mode; + sys_nlink_t st_nlink; + sys_uid_t st_uid; + sys_gid_t st_gid; + sys_dev_t st_rdev; + sys_off_t st_size; + struct sys_timespec st_atim; + struct sys_timespec st_mtim; + struct sys_timespec st_ctim; + sys_blksize_t st_blksize; + sys_blkcnt_t st_blocks; + +} sys_stat_t; + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/include/systypes/timespec.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/include/systypes/timespec.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,39 @@ +/* + * Time-related types. + * + * Copyright (C) 2019 Paul Boddie + * + * 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 + */ + +#pragma once + +#include + +EXTERN_C_BEGIN + +/* Equivalent types are defined in sys/timespec.h typically. In newlib, they are + defined in sys/_timespec.h. */ + +typedef __INT64_TYPE__ sys_time_t; + +struct sys_timespec +{ + sys_time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; + +EXTERN_C_END diff -r 40dc1cbd5356 -r 49d8e9637cdb libsystypes/include/systypes/user.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/include/systypes/user.h Wed Aug 25 01:28:08 2021 +0200 @@ -0,0 +1,39 @@ +/* + * User abstractions. + * + * Copyright (C) 2019, 2021 Paul Boddie + * + * 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 + */ + +#pragma once + +#include +#include + +EXTERN_C_BEGIN + +/* User abstraction. */ + +typedef struct +{ + sys_uid_t uid; + sys_gid_t gid; + sys_mode_t umask; + +} user_t; + +EXTERN_C_END