├── CHANGELOG ├── LICENSE ├── README.md ├── devnotes ├── flashnul.conf ├── flashnul.png ├── readme.eng ├── readme.rus.html ├── src ├── Makefile ├── actions.c ├── actions.h ├── advanced.c ├── advanced.h ├── colian │ ├── Makefile │ ├── base.c │ ├── clatypes.h │ ├── cmd.c │ ├── colian.h │ ├── dbg.c │ ├── env.c │ ├── group.c │ ├── i18n.h │ ├── init-close.c │ ├── internal.h │ ├── join.c │ ├── print.c │ ├── read.c │ └── write.c ├── common.c ├── common.h ├── ddk.h ├── detect.c ├── detect.h ├── display.c ├── display.h ├── finetune.h ├── flashnul.c ├── flashnul.h ├── generate.c ├── generate.h ├── io.c ├── io.h └── sample └── todo /CHANGELOG: -------------------------------------------------------------------------------- 1 | v 1.0rc1 (0.994) 2 | - bug with counter overflow (@ some CPUs) 3 | (bugreport by Alexander Matveev Alexander.Matveev[at]teleca.com) 4 | 5 | v 0.993 6 | * minor changes in makefile 7 | + int64 support for options (no more 2Gb limit for -r option) 8 | 9 | v 0.992 10 | - stupid bug with -p option 11 | * note for double-clickers 12 | 13 | v 0.991 14 | 15 | - image file do not locking (FILE_SHARE_READ) while loading to media 16 | + allow parallel image loading by few copies of flashnul 17 | (bugreport by Mick T. Lyalin lialin[at]yandex.ru) 18 | * small behavior changes for -h/-v options 19 | 20 | v 0.99 21 | * minor fixes 22 | + update mode 23 | 24 | v 0.9 25 | + 99 (insead 9) drive support 26 | + speed counters 27 | * incresized speed of block operations (r/w) 28 | - bug with duplicate --block option. 29 | - bug with permanent "0%" in delta size in report 30 | + configuration file "flashnul.conf" 31 | + block-letter and block-number options 32 | 33 | v 0.8 34 | * FILE_SHARE_READ|FILE_SHARE_WRITE changed to FILE_SHARE_READ. 35 | + new key --write-share for enabling write share. 36 | * new physical drive list. 37 | + new information (bus, removablility, serial number, name). 38 | + option -p now take a parameter (bitset of tests). 39 | - waiting time at the test end if drive size unknown. 40 | - -V mode trap for --load option. 41 | + keys for block writing (see help, --block-* options) 42 | 43 | v 0.7 44 | 45 | ! new drive size detection (bug with 'invisible' surplus sectors) 46 | - minor UI bug in bitdump 47 | - image file (-L/-S) do not close until end of program 48 | - -T option override -d,-V,-m options 49 | * minor changes in logical disk list 50 | 51 | v 0.6 52 | + -T option as set of (-I -V=3 -m=1 options) 53 | + bitdump in case of difference of wrote and reed (first 16 bytes) 54 | + -k option for disable [Enter] prompt at exit 55 | - minor bug with default values 56 | - minor UI bugs with leftover ')' on screen 57 | ? warning messages at run 58 | 59 | v 0.5 60 | 61 | * now "Press [Enter] to exit" apear even in case of error. 62 | - memory leak in -V=0 mode 63 | + -d (--delay) option to set delay before re-read test (in sec) 64 | + -m (--mode) modes for -I test (-m=0, -m=1) 65 | 66 | v 0.4 67 | - minor fix in generate.c (check for size of allocation memory) 68 | * option -r renamed to -R 69 | * parameters from -R, -I, -F options moved to -b option. 70 | + --load (-L) option (load image to disk) 71 | + --save (-S) option (save image from disk to file) 72 | + --block-size (-b) option for I/O operation 73 | + --range (-r) option for -S, -L, -F and -I options for set I/O range. 74 | + argument for -F (fill value) 75 | + argument for -I (init value) 76 | 77 | v 0.3 78 | 79 | * small improvment in human_view(). 80 | + logical disks list in -p mode. 81 | * now GetDiskFreeSpace() do not calling for physical drives. 82 | - error with encoding for error messages in non-english Windows. 83 | 84 | v 0.2 85 | first public release 86 | 87 |  -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | USB-flash testing utility 294 | Copyright (C) 2013 George Shuklin 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | flashnul 2 | ======== 3 | 4 | USB-flash testing utility 5 | 6 | **Archival notice**: This is very old piece of software I wrote few decades ago. It was converted to git and uploaded for github for archival reasons only. 7 | 8 | I do not maintain it or able to rebuild it. Feel free to fork if you need it. About 90% of it's functions can be replicated with `dd` binary (from coreutils package). 9 | -------------------------------------------------------------------------------- /devnotes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amarao/flashnul/0c6b3422e9a4eda3539638af93cc856b06fa0e9e/devnotes -------------------------------------------------------------------------------- /flashnul.conf: -------------------------------------------------------------------------------- 1 | # - sign of comment 2 | 3 | ###################### 4 | ### USER INTERFACE ### 5 | ###################### 6 | 7 | #disable-key 8 | ##disable message 'Press ENTER to exit' at the end of application. 9 | 10 | 11 | #no-prompt 12 | ##disable confirmation message before destructive tests 13 | ##WARNING! USE CAREFULLY! 14 | 15 | ####################### 16 | ### CONTORL OPTIONS ### 17 | ####################### 18 | 19 | #write-share 20 | ##enable write-share by default 21 | 22 | #delay=10 23 | ##delay before reread test (in s) 24 | 25 | 26 | ##################### 27 | ### BLOCK SECTION ### 28 | ##################### 29 | 30 | #block-bus=SCSI;ISCSI 31 | #block devices by bus type 32 | #possible values (can be separated by ';'): 33 | # UNKNOWN, SCSI, ATAPI, ATA, IEEE1394, SSA, FIBRE, USB, RAID, ISCSI, SAS, SATA 34 | # or number [0-11] - (UNKNOWN=0, SCSI=1,...,USB=7,etc). 35 | 36 | 37 | #block-non-removable 38 | #block all non-removable devices 39 | #possible values 0,1 40 | 41 | #block-vendor=Pretec;ICSI 42 | #block all devices with substring within vendor name 43 | #block-vendor=a will block all devices with letter 'a' in vendor name, 44 | #possible values: strings, separated by ';' (no spaces allowed) 45 | #note: not applicable to devices without vendor name 46 | 47 | block-name=ST310211A 48 | #block all devices with substring within device name 49 | #possible values: strings, separated by ';' 50 | #note: not applicable to devices without device name 51 | 52 | #block-serial=FV45664;544465666544;DE34545S-D 53 | #block all (?) devices with substring within serial number 54 | #possible values: strings, separated by ';' 55 | #note: not applicable to devices without serial 56 | 57 | block-letter=C 58 | #block-letter=CD;EFG;H;Z 59 | #block by drive letter 60 | 61 | block-number=0 62 | #block-number=0;1;2;3;4;5;99 63 | #block by drive number 64 | -------------------------------------------------------------------------------- /flashnul.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amarao/flashnul/0c6b3422e9a4eda3539638af93cc856b06fa0e9e/flashnul.png -------------------------------------------------------------------------------- /readme.eng: -------------------------------------------------------------------------------- 1 | Flashnul - utility for flash-drives diagnostic (flash-USB, MMC, SD, XD, 2 | SmartMedia, CompactFlash, etc). 3 | 4 | Detecting defects: 5 | * write/read errors 6 | * data loss 7 | * incorrect writing (errors in sector address) 8 | 9 | Features: 10 | * reading/writing raw images 11 | * error bits dump 12 | 13 | For usage call flashnul --help for options list. 14 | 15 | NOTE: SOME TESTS ARE DESTRUCTIVE. USE CAREFULLY. 16 | 17 | sys.req.: any PC under Windows 2000/XP/2003S. (NT4 - not tested). 18 | Utility use write access to Physical Drives and can 19 | fail if runned under restricted (non-Administrator) account. 20 | 21 | licence: GNU GPL (see copying for detail). 22 | 23 | P.S. Sorry, English is not my strong side. 24 | 25 | (c) George Shuklin, 2005-2007, gs@shounen.ru, http://shounen.ru/soft/flashnul 26 | -------------------------------------------------------------------------------- /readme.rus.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amarao/flashnul/0c6b3422e9a4eda3539638af93cc856b06fa0e9e/readme.rus.html -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | cc = gcc 2 | obj = flashnul.o generate.o io.o display.o actions.o common.o detect.o advanced.o 3 | out = flashnul.exe 4 | CFLAGS = --pipe -O2 -march=i686 -Wall 5 | 6 | all: $(obj) colian/libcolian.a 7 | gcc $(obj) $(OPT) -L colian -lcolian -lkernel32 -o $(out) 8 | strip $(out) 9 | cp flashnul.exe .. 10 | 11 | colian/libcolian.a: 12 | make -C colian 13 | 14 | clean: 15 | make clean -C colian 16 | rm *.o flashnul.exe 17 | 18 | redo: clean all -------------------------------------------------------------------------------- /src/actions.c: -------------------------------------------------------------------------------- 1 | /*actions (-F, -I, etc)*/ 2 | #include 3 | #include 4 | #include 5 | #include "io.h" 6 | #include "generate.h" 7 | #include "display.h" 8 | #include "colian/colian.h" 9 | #include "flashnul.h" 10 | #include "actions.h" 11 | #include "common.h" 12 | 13 | #define DUMP_SIZE 16 14 | 15 | int compare_blocks( unsigned char* one, unsigned char* two, long long size, long long offset ){ 16 | 17 | long long diff_counter=0; 18 | if( !size ) 19 | return 0; 20 | 21 | diff_counter=compare_mem(one,two,size); 22 | 23 | if( !diff_counter ) 24 | return 1; 25 | else{ 26 | printf("\nERROR: verification failed (read/write data mismatch)\t\t \n"); 27 | printf("errors: %I64d, offset: 0x%I64x (%I64d), block size: %I64d\n",diff_counter,offset, offset, size); 28 | if(diff_counter= end_value ) 48 | return 0; 49 | if( prefere_size ) 50 | if( offset+prefere_size < end_value ) 51 | return prefere_size; 52 | if( offset+DEFAULT_BLOCK_SIZE < end_value ) 53 | return DEFAULT_BLOCK_SIZE; 54 | 55 | return end_value-offset; 56 | 57 | } 58 | 59 | 60 | void blank( dev_ctrl_t* dev, io_ctrl_t* io_ctrl ){ 61 | 62 | unsigned char* bulk = NULL; 63 | unsigned char* res_bulk= NULL; 64 | int result = 0; 65 | long long offset = io_ctrl->start; 66 | 67 | dev->block_size = dev->sector_size; 68 | bulk = create_filled_block( dev->sector_size, 0 ); 69 | assert( bulk ); 70 | 71 | result = write_block( dev, offset, bulk, dev->sector_size ); 72 | if( io_ctrl->ignore_error ){ 73 | read_block( dev, offset, &res_bulk, dev->sector_size ); 74 | if(!compare_blocks(bulk, res_bulk, dev->sector_size, offset )) 75 | dev->error_count++; 76 | 77 | }else{ 78 | 79 | if( result ){ 80 | printf( "\rWriting first sector - ok\n" ); 81 | 82 | result = read_block( dev, offset, &res_bulk, dev->sector_size ); 83 | if( result ){ 84 | printf( "\rReading first sector - ok\n") ; 85 | 86 | if( !compare_blocks ( bulk,res_bulk, dev->sector_size, offset )){ 87 | dev->error_count++; 88 | exit( -1 ); 89 | }else 90 | printf( "\rVerifying first sector - ok\n" ); 91 | 92 | } 93 | 94 | }else 95 | exit( -1 ); 96 | 97 | } 98 | 99 | free( bulk ); 100 | free( res_bulk ); 101 | dev->pass_count++; 102 | 103 | } 104 | 105 | void msg_sleep(int time){ 106 | clearline(); 107 | fprintf(stderr,"\rwaiting %d sec (Ctrl-C to cancel)",time); 108 | Sleep(time*1000); 109 | fprintf(stderr,"\r "); 110 | } 111 | 112 | void fill( dev_ctrl_t* dev, int byte, io_ctrl_t* io_ctrl ){ 113 | 114 | long long offset = io_ctrl->start; 115 | 116 | long long block_size = 0; 117 | unsigned char* block = 0; 118 | unsigned char* res_block = NULL; 119 | static int counter = 0; 120 | int result = 0; 121 | 122 | 123 | block_size = get_next_block_size( offset, dev->size, io_ctrl->block_size, io_ctrl->end ); 124 | dev->block_size = block_size; 125 | block = create_filled_block( block_size, (unsigned char) byte ); 126 | assert( block ); 127 | 128 | res_block = NULL; 129 | 130 | if( !block_size ) 131 | printf("Device size unknown: test skipped\n"); 132 | 133 | 134 | while( block_size ){ 135 | 136 | result = write_block(dev, offset, block , block_size ); 137 | 138 | if( !result && !io_ctrl->ignore_error ) 139 | exit( -1 ); 140 | 141 | if( io_ctrl->verify_mode & 1 ){ 142 | 143 | result = read_block( dev, offset, &res_block, block_size ); 144 | if( !result && !io_ctrl->ignore_error ) 145 | exit( -1 ); 146 | 147 | if( !compare_blocks(block,res_block, block_size, offset ) ){ 148 | dev->error_count++; 149 | if( !io_ctrl->ignore_error ) 150 | exit(-1); 151 | } 152 | free( res_block ); 153 | res_block = NULL; 154 | 155 | } 156 | 157 | offset += block_size; 158 | block_size = get_next_block_size( offset, dev->size, io_ctrl->block_size, io_ctrl->end ); 159 | 160 | } 161 | 162 | /*verification mode 2 (read all after writing all) */ 163 | 164 | if( io_ctrl->verify_mode & 2 ){ 165 | 166 | if( io_ctrl->delay && dev->size ){ 167 | msg_sleep(io_ctrl->delay); 168 | } 169 | 170 | offset = io_ctrl->start; 171 | block_size = get_next_block_size (offset, dev->size, io_ctrl->block_size, io_ctrl->end ); 172 | 173 | while (block_size){ 174 | 175 | result = read_block( dev, offset, &res_block, block_size ); 176 | if( !result && !io_ctrl->ignore_error ) 177 | exit ( -1 ); 178 | 179 | if( !compare_blocks( block,res_block,block_size, offset ) ){ 180 | dev->error_count++; 181 | if( !io_ctrl->ignore_error ) 182 | exit(-1); 183 | } 184 | free( res_block ); 185 | res_block = NULL; 186 | 187 | offset += block_size; 188 | block_size = get_next_block_size( offset, dev->size, io_ctrl->block_size, io_ctrl->end ); 189 | 190 | } 191 | 192 | } 193 | free( block ); 194 | clearline(); 195 | printf( "\rdevice filled (pass #%d) \n", ++counter ); 196 | dev->pass_count++; 197 | 198 | } 199 | 200 | 201 | 202 | 203 | void inc_fill( dev_ctrl_t *dev, int start_offset, io_ctrl_t *io_ctrl ){ 204 | long long block_size; 205 | long long offset = io_ctrl->start; 206 | unsigned char* block; 207 | unsigned char* res_block=NULL; 208 | int result; 209 | static int counter=0; 210 | static int iterator = 0; 211 | 212 | block_size = get_next_block_size( offset, dev->size, io_ctrl->block_size, io_ctrl->end ); 213 | dev->block_size = block_size; 214 | 215 | if( !block_size ||!dev->size ) 216 | printf("Unable to detect drive size, test skipped\n"); 217 | 218 | res_block=NULL; 219 | while( block_size ){ 220 | if( iterator == 0 ) 221 | iterator = start_offset; 222 | block = create_test_block ( offset, dev->sector_size, block_size, counter, io_ctrl->mode ); 223 | assert(block); 224 | result = write_block(dev, offset, block , block_size ); 225 | if( !result && !io_ctrl->ignore_error ) 226 | exit( -1 ); 227 | 228 | if( io_ctrl->verify_mode & 1 ){ 229 | result = read_block( dev, offset, &res_block, block_size ); 230 | if( !result && !io_ctrl->ignore_error ) 231 | exit(-1); 232 | if( !compare_blocks( block, res_block,block_size, offset ) ){ 233 | dev->error_count++; 234 | if( !io_ctrl->ignore_error) 235 | exit(-1); 236 | } 237 | free( res_block ); 238 | res_block = NULL; 239 | } 240 | free(block); 241 | block=NULL; 242 | offset += block_size; 243 | block_size = get_next_block_size( offset, dev->size, io_ctrl->block_size, io_ctrl->end ); 244 | } 245 | 246 | if( io_ctrl->verify_mode & 2 ){ 247 | 248 | if(io_ctrl->delay && dev->size && block_size ){ 249 | msg_sleep(io_ctrl->delay); 250 | } 251 | 252 | offset=io_ctrl->start; 253 | block_size = get_next_block_size (offset, dev->size,io_ctrl->block_size, io_ctrl->end ); 254 | while( block_size ){ 255 | block = create_test_block ( offset, dev->sector_size, block_size, counter, io_ctrl->mode ); 256 | assert(block); 257 | result = read_block( dev, offset, &res_block, block_size ); 258 | if(!result && !io_ctrl->ignore_error ) 259 | exit (-1); 260 | if(!compare_blocks( block,res_block,block_size, offset ) ){ 261 | dev->error_count++; 262 | if( !io_ctrl->ignore_error ) 263 | exit(-1); 264 | } 265 | free(res_block); 266 | res_block=NULL; 267 | free(block); 268 | block=NULL; 269 | offset += block_size; 270 | block_size = get_next_block_size( offset, dev->size,io_ctrl->block_size, io_ctrl->end ); 271 | } 272 | } 273 | clearline(); 274 | iterator=offset; 275 | if(dev->size){ 276 | dev->pass_count++; 277 | printf("\rpass #%d ended \n",++counter); 278 | } 279 | 280 | } 281 | 282 | 283 | void read_test( dev_ctrl_t* dev, io_ctrl_t* io_ctrl ){ 284 | long long block_size; 285 | long long offset = io_ctrl->start; 286 | unsigned char* block=NULL; 287 | static int counter=0; 288 | int result; 289 | 290 | block_size = get_next_block_size (offset, dev->size,io_ctrl->block_size, io_ctrl->end ); 291 | dev->block_size = block_size; 292 | 293 | while (block_size){ 294 | result = read_block( dev, offset, &block, block_size ); 295 | if( !result && !io_ctrl->ignore_error) 296 | exit(-1); 297 | offset+=block_size; 298 | block_size = get_next_block_size (offset, dev->size, io_ctrl->block_size, io_ctrl->end ); 299 | } 300 | free( block ); 301 | clearline(); 302 | printf("\rread test (pass #%d) \n",++counter); 303 | dev->pass_count++; 304 | 305 | } 306 | 307 | void save_image( dev_ctrl_t* dev, const char* name, io_ctrl_t* io_ctrl ){ 308 | HANDLE sav_target; 309 | long long block_size=0; 310 | unsigned char* block=NULL; 311 | long long offset=io_ctrl->start; 312 | int result; 313 | int std_flag=0; 314 | int pref_size=0; 315 | DWORD written; 316 | if( !strncmp(name,"-",2)){ 317 | 318 | sav_target=GetStdHandle(STD_OUTPUT_HANDLE); 319 | std_flag=1; 320 | if( io_ctrl->block_size ) 321 | pref_size=io_ctrl->block_size; 322 | else 323 | pref_size=4096; 324 | 325 | }else{ 326 | sav_target = CreateFile( name, GENERIC_WRITE|GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL ); 327 | } 328 | if(sav_target==INVALID_HANDLE_VALUE){ 329 | printf("Unable to open file %s, %s\n",name, error_text()); 330 | return; 331 | } 332 | dev->block_size = pref_size; 333 | block_size = get_next_block_size (offset, dev->size, pref_size, io_ctrl->end ); 334 | while( block_size ){ 335 | result= read_block( dev, offset, &block, block_size ); 336 | if( !result && !io_ctrl->ignore_error ) 337 | exit(-1); 338 | result=WriteFile( sav_target, block, (DWORD)block_size,(LPDWORD)&written, NULL ); 339 | if( !result ){ 340 | printf("error: %s\n",error_text()); 341 | if( !io_ctrl->ignore_error ) 342 | exit(-1); 343 | } 344 | if(written!=(DWORD)block_size){ 345 | printf("block not fully copyied (%u of %I64d)\n",(unsigned int)written,block_size); 346 | if(! io_ctrl->ignore_error) 347 | exit(-1); 348 | } 349 | 350 | free(block); 351 | block=NULL; 352 | offset+=block_size; 353 | block_size = get_next_block_size (offset, dev->size, pref_size, io_ctrl->end ); 354 | } 355 | if(!std_flag) 356 | CloseHandle(sav_target); 357 | free(block); 358 | printf("\nsave finished\n"); 359 | dev->pass_count++; 360 | 361 | } 362 | 363 | 364 | void load_image( dev_ctrl_t* dev, const char* name, io_ctrl_t* io_ctrl ){ 365 | 366 | HANDLE load_target; 367 | long long block_size = 0; 368 | unsigned char* block = NULL; 369 | unsigned char* res_block = NULL; 370 | long long offset = io_ctrl->start; 371 | int result; 372 | int std_flag = 0; 373 | int pref_size = 0; 374 | // DWORD written; 375 | DWORD loaded; 376 | 377 | 378 | if( !strncmp(name,"-",2)){/*stdin*/ 379 | 380 | load_target = GetStdHandle( STD_INPUT_HANDLE ); 381 | if( load_target == INVALID_HANDLE_VALUE ){ 382 | printf( "Unable to open stdin (bug?)\n"); 383 | return; 384 | } 385 | std_flag = 1; 386 | if( io_ctrl->block_size ) 387 | pref_size = io_ctrl->block_size; 388 | else 389 | pref_size = 4096; 390 | 391 | }else{ 392 | load_target = CreateFile( name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); 393 | pref_size = io_ctrl->block_size; 394 | } 395 | if( load_target == INVALID_HANDLE_VALUE ){ 396 | printf(" Unable to open file %s. %s\n", name, error_text() ); 397 | return; 398 | } 399 | 400 | dev->block_size = pref_size; 401 | block_size = get_next_block_size (offset, dev->size, pref_size, io_ctrl->end ); 402 | 403 | while( block_size ){ 404 | 405 | block = malloc( (size_t)block_size ); 406 | assert(block); 407 | 408 | result = ReadFile( load_target, block, (DWORD)block_size, (LPDWORD)&loaded, NULL ); 409 | if( !result ){/*io_ctrl->ignore_error do not work here!*/ 410 | printf("file %s:%s\n", name, error_text() ); 411 | exit(-1); 412 | } 413 | if( !loaded ) 414 | break; 415 | if(block_size!=loaded){ 416 | if(dev->sector_size){ 417 | if( loaded%dev->sector_size ){ 418 | printf("\nWarning: size of file %s do not match sector size for %s (%I64d b)\n",name, dev->user_name, dev->sector_size); 419 | memset(block+loaded,0,block_size-loaded); 420 | if((loaded/dev->sector_size+1)*dev->sector_size <= block_size ) 421 | block_size = (loaded/dev->sector_size+1)*dev->sector_size; 422 | else{ 423 | printf("\nInternal error, sector size is too large (%I64d)\n",dev->sector_size); 424 | exit(-1); 425 | } 426 | }else 427 | block_size = loaded; 428 | }else 429 | block_size=loaded; 430 | } 431 | result = write_block( dev, offset, block, block_size ); 432 | if(!result && !io_ctrl->ignore_error ) 433 | exit (-1); 434 | 435 | if( io_ctrl->verify_mode ){ 436 | res_block = malloc( (size_t)block_size ); 437 | result = read_block( dev, offset, &res_block, block_size ); 438 | if( ! result && !io_ctrl->ignore_error ) 439 | exit(-1); 440 | if(!compare_blocks( block,res_block,block_size, offset ) ){ 441 | dev->error_count++; 442 | if(!io_ctrl->ignore_error) 443 | exit(-1); 444 | } 445 | free( res_block ); 446 | } 447 | offset += block_size; 448 | block_size = get_next_block_size( offset, dev->size, pref_size, io_ctrl->end ); 449 | free (block); 450 | } 451 | if(!std_flag) 452 | CloseHandle( load_target ); 453 | printf("\nimage load finished\n"); 454 | dev->pass_count++; 455 | } 456 | 457 | 458 | void quick_test ( dev_ctrl_t* dev, io_ctrl_t* io_ctrl ){ 459 | /*content of test: try to write/read a base*sector_size block in each block_size block 460 | 461 | */ 462 | long long test_block_size = 0; 463 | long long skipped_block_size = 0; /*include test_block_size*/ 464 | long long current_offset = 0; /*todo -r option support*/ 465 | unsigned char* primary = NULL; 466 | unsigned char* secondary = NULL; 467 | unsigned char* pattern = NULL; 468 | 469 | 470 | if( dev->sector_size ) 471 | test_block_size = dev->sector_size; 472 | else 473 | test_block_size = 512; 474 | 475 | if ( io_ctrl->block_size ) 476 | skipped_block_size = io_ctrl->block_size; 477 | else 478 | skipped_block_size = 65536; 479 | 480 | if( test_block_size <= 0 || skipped_block_size <=0 || test_block_size < skipped_block_size ){ 481 | test_block_size = 512; 482 | skipped_block_size = 65536; 483 | } 484 | 485 | primary = calloc( test_block_size, 1 ); 486 | secondary = calloc( test_block_size, 1 ); 487 | pattern = create_test_block( current_offset, test_block_size, test_block_size, 0, 1); 488 | 489 | assert( primary && secondary ); 490 | 491 | while( current_offset < dev->size ){ 492 | if( !read_block( dev, current_offset, &primary, test_block_size ) && !io_ctrl->ignore_error ) 493 | return; 494 | /* if( !write_block( dev, current_offset, pattern, test_block_size ) && !io_ctrl->ignore_error ) 495 | return; 496 | if( !read_block( dev, current_offset, &secondary, test_block_size ) && !io_ctrl->ignore_error ) 497 | return; 498 | if( !compare_blocks( pattern, secondary, test_block_size, current_offset ) ){ 499 | dev->error_count++; 500 | if( !io_ctrl->ignore_error ) 501 | return; 502 | }*/ 503 | if( !write_block( dev, current_offset, primary, test_block_size ) && !io_ctrl->ignore_error ) 504 | return; 505 | if( !read_block( dev, current_offset, &secondary, test_block_size ) && !io_ctrl->ignore_error ) 506 | return; 507 | if( !compare_blocks( primary, secondary, test_block_size, current_offset ) ){ 508 | dev->error_count++; 509 | if( !io_ctrl->ignore_error ) 510 | return; 511 | } 512 | current_offset+=skipped_block_size; 513 | } 514 | if( !dev->error_count ) 515 | printf( "\nquick test passed, no error founds, please run a full test (-T)\n" ); 516 | else 517 | printf( "\nquick test found a %I64d errors\n", dev->error_count ); 518 | dev->pass_count++; 519 | free(primary); 520 | free(secondary); 521 | 522 | } 523 | 524 | 525 | void update_action( dev_ctrl_t* dev, io_ctrl_t* io_ctrl ){ 526 | 527 | long long block_size; 528 | long long offset = io_ctrl->start; 529 | unsigned char* primary = NULL; 530 | unsigned char* secondary = NULL; 531 | 532 | block_size = get_next_block_size (offset, dev->size,io_ctrl->block_size, io_ctrl->end ); 533 | dev->block_size = block_size; 534 | 535 | primary = calloc( block_size, 1 ); 536 | secondary = calloc( block_size, 1 ); 537 | assert( primary && secondary ); 538 | 539 | while (block_size){ 540 | 541 | if( !read_block( dev, offset, &primary, block_size ) && !io_ctrl->ignore_error ) 542 | return; 543 | if( !write_block( dev, offset, primary, block_size ) && !io_ctrl->ignore_error ) 544 | return; 545 | if( !read_block( dev, offset, &secondary, block_size ) && !io_ctrl->ignore_error ) 546 | return; 547 | if( !compare_blocks( primary, secondary, block_size, offset ) ){ 548 | dev->error_count++; 549 | if( !io_ctrl->ignore_error ) 550 | return; 551 | } 552 | offset += block_size; 553 | block_size = get_next_block_size( offset, dev->size, io_ctrl->block_size, io_ctrl->end ); 554 | } 555 | free( secondary ); 556 | free( primary ); 557 | 558 | } 559 | 560 | 561 | 562 | 563 | 564 | void get_drive_info(dev_ctrl_t* dev, int scan, int silence ){ 565 | 566 | 567 | 568 | if(scan & FLASHNUL_GEOMETRY_SCAN){ 569 | 570 | if( get_drive_geometry( dev ) ){ 571 | dev->drive_geometry_flag = 1; 572 | } 573 | else{ 574 | if( !silence ) 575 | printf("DeviceIoCtrl() / IOCTL_DISK_GET_DRIVE_GEOMETRY failed: %s",error_text()); 576 | dev->detection_error++; 577 | } 578 | 579 | } 580 | 581 | if( !dev->physical_flag && scan & FLASHNUL_FREESPACE_SCAN ){ 582 | 583 | if( get_free_space( dev ) ) 584 | dev->disk_space_flag = 1; 585 | else 586 | if( !silence ) 587 | printf("GetFreeDiskSpaceEx() failed: %s", error_text() ); 588 | 589 | } 590 | 591 | if( scan & FLASHNUL_DEVICE_SIZE_SCAN ){ 592 | 593 | dev->device_size = get_device_size( dev ); 594 | if( dev->device_size >= 0 ) 595 | dev->drive_length_flag = 1; 596 | else{ 597 | dev->detection_error++; 598 | if( !silence ) 599 | printf( "DeviceIOControl() / IOCTL_DISK_GET_LENGTH_INFO failed: (%I64d) %s", dev->device_size, error_text() ); 600 | if( dev->device_size == -1 ) 601 | dev->device_size =0; 602 | } 603 | 604 | } 605 | 606 | if( scan & FLASHNUL_ADAPTER_PROPERTIES_SCAN ){ 607 | 608 | if( get_adapter_property( dev ) ) 609 | dev->adapter_flag = 1; 610 | else 611 | if( !silence ) 612 | printf( "DeviceIOControl() / IOCTL_STORAGE_QUERY_PROPERTY (adapter) failed: %s", error_text() ); 613 | 614 | 615 | } 616 | 617 | if( scan & FLASHNUL_DEVICE_PROPERTIES_SCAN ){ 618 | 619 | if( get_device_property( dev ) ) 620 | dev->device_flag = 1; 621 | else 622 | if( !silence ) 623 | printf( "DeviceIOControl() / IOCTL_STORAGE_QUERY_PROPERTY (device) failed: %s", error_text() ); 624 | 625 | } 626 | 627 | if( scan & FLASHNUL_HOTPLUG_SCAN ){ 628 | if(! get_device_hotplug_info( dev ) ) 629 | if(! silence ) 630 | printf( "DeviceIOControl() / IOCTL_STORAGE_GET_HOTPLUG_INFO filed: %s", error_text() ); 631 | } 632 | select_device_size( dev ); 633 | } 634 | 635 | void select_device_size ( dev_ctrl_t* dev ){ 636 | if(isdigit(dev->user_name[0])||dev->user_name[0]=='\\'){ /*physical drive or UNC*/ 637 | dev->size = max( max(dev->geometry_size, dev->disk_size), dev->device_size ); 638 | } 639 | if(isalpha(dev->user_name[0])){ /*logical drive*/ 640 | if( dev->device_size ) 641 | dev->size = dev->device_size ; 642 | else 643 | dev->size = max( max(dev->geometry_size, dev->disk_size), dev->device_size ); 644 | } 645 | } 646 | 647 | -------------------------------------------------------------------------------- /src/actions.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_ACTIONS_H 2 | #define _H_ACTIONS_H 3 | void blank( dev_ctrl_t* dev, io_ctrl_t* io_ctrl ); 4 | void fill( dev_ctrl_t* dev, int byte, io_ctrl_t* io_ctrl ); 5 | void inc_fill( dev_ctrl_t *dev, int start_offset, io_ctrl_t *io_ctrl ); 6 | void read_test( dev_ctrl_t* dev, io_ctrl_t* io_ctrl ); 7 | void save_image( dev_ctrl_t* dev, const char* name, io_ctrl_t* io_ctrl ); 8 | void load_image( dev_ctrl_t* dev, const char* name, io_ctrl_t* io_ctrl ); 9 | void quick_test ( dev_ctrl_t* dev, io_ctrl_t* io_ctrl ); 10 | void update_action( dev_ctrl_t* dev, io_ctrl_t* io_ctrl ); 11 | 12 | void select_device_size ( dev_ctrl_t* dev ); 13 | void get_drive_info(dev_ctrl_t* dev, int scan, int silence ); 14 | enum{ 15 | FLASHNUL_GEOMETRY_SCAN = 0x1, 16 | FLASHNUL_FREESPACE_SCAN = 0x2, 17 | FLASHNUL_DEVICE_SIZE_SCAN = 0x4, 18 | FLASHNUL_ADAPTER_PROPERTIES_SCAN = 0x8, 19 | FLASHNUL_DEVICE_PROPERTIES_SCAN = 0x10, 20 | FLASHNUL_HOTPLUG_SCAN = 0x20, 21 | FLASHNUL_DEBUG_INFO = 0x80 22 | }; 23 | 24 | 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/advanced.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Advanced recovery mode allow to save image (not fully) from 4 | hanguping devices. Standard recovery software do not allow to 5 | unplug devices during saving and plug it back without restarting 6 | recovery process. 7 | 8 | This mode deisgned espesially for flash (sd/mmc/etc) and (may be) 9 | for CD (dvd/bd) disks. 10 | 11 | Algorithm: 12 | 13 | saving image. If error happens: 14 | * close device 15 | * wait for user conformation (and repluging a hangupped device) 16 | * reopen device 17 | * seek to error place + offset 18 | * fill a skipped space by fill_byte value in output file 19 | * continue saving 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | /*void advanced_recovery ( 27 | const char* dev_name, 28 | const char* name, 29 | const char* skip, //converted to number 30 | const char* fill, //converted to number 31 | ){ 32 | 33 | HANDLE input_device; 34 | HANDLE output_file; 35 | FILE* log_file; 36 | unsigned char* output_name[MAX_PATH+1]; 37 | unsigned char log_name[MAX_PATH+1]; 38 | unsigned char fill_byte; 39 | long long skip_size; 40 | long long offset = 0; 41 | 42 | snprintf( output_name, MAX_PATH, "%s.ARimage",name ); 43 | snprintf( log_name, MAX_PATH, "%s.ARlog",name ); 44 | 45 | output_file = CreateFile( output_name, GENERIC_WRITE|GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL ); 46 | if( output_file == INVALID_HANDLE_VALUE ){ 47 | printf( "sorry, unable to create new file %s\n", output_file ); 48 | return; 49 | } 50 | output_log = fopen(log_name, "w"); 51 | if( !output_log ){ 52 | printf( "sorry, unable to open log file %s\n", output_log ); 53 | return; 54 | } 55 | 56 | printf("** Advanced recovery mode started. If device hand up during saving, unplug it, plug back and press [Enter] key (or input a different seek value)\n"); 57 | 58 | 59 | 60 | } 61 | */ 62 | -------------------------------------------------------------------------------- /src/advanced.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_ADVANCED_H 2 | #define _H_ADVANCED_H 3 | 4 | void advanced_recovery ( 5 | dev_ctrl_t* dev, 6 | const char* name, 7 | const char* skip, //converted to number 8 | const char* fill, //converted to number 9 | io_ctrl_t* io_ctrl ); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/colian/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS =-O3 --pipe 3 | #SRC = base.c cmd.c dbg.c get.c group.c init-close.c join.c print.c read.c write.c env.c 4 | OBJ = base.o cmd.o dbg.o group.o init-close.o join.o print.o read.o write.o env.o 5 | 6 | all: libcolian.a 7 | 8 | libcolian.a: $(OBJ) 9 | ar cr libcolian.a $(OBJ) 10 | ranlib libcolian.a 11 | 12 | clean: 13 | rm $(OBJ) 14 | rm libcolian.a -------------------------------------------------------------------------------- /src/colian/base.c: -------------------------------------------------------------------------------- 1 | #include "colian.h" 2 | #include "internal.h" 3 | #include "i18n.h" 4 | 5 | char* SkipSpaces( const char* line ){ 6 | 7 | int i = 0; 8 | 9 | while( line[i] == ' ' || line[i] == '\t' ) 10 | i++; 11 | 12 | return (char*)( line + i ); 13 | } 14 | 15 | int OptNameCmp( const char* sample, const char* name, int case_ignore_flag ){ 16 | /*return: 17 | <0 - error in comparing 18 | >1 - compare ok, return value points to end of name (e.g. to '=' or ':') 19 | 0 - compare ok, no '=' or ':' at the end*/ 20 | 21 | int c = 0; 22 | 23 | if( case_ignore_flag ){ 24 | while( name[c] ){ 25 | if( toupper( sample[c] ) != toupper( name[c] )) 26 | return -1; 27 | c++; 28 | } 29 | }else{ 30 | while( name[c] ){ 31 | if( sample[c] != name[c] ) 32 | return -1; 33 | c++; 34 | } 35 | } 36 | 37 | if( sample[c] == ':' || sample[c] == '=' ) 38 | return c; 39 | 40 | if( !sample[c] || sample[c]==' ' || sample[c]=='\t') 41 | return 0; 42 | 43 | return -1; 44 | 45 | } 46 | 47 | 48 | 49 | char* SkipEquiv(const char* line){ 50 | 51 | char* c = SkipSpaces(line); 52 | 53 | if( *c != '=' ) 54 | return ""; 55 | 56 | c++; 57 | 58 | return SkipSpaces(c); 59 | 60 | } 61 | 62 | 63 | 64 | /** 65 | * return order number of long option, or -1 if option not found. 66 | * valid OptList array requied 67 | **/ 68 | 69 | 70 | 71 | int GetOptionID( 72 | const char* line, 73 | const claOptName_t* OptList, 74 | const int OptListNum, 75 | int type 76 | ){ 77 | 78 | int c; 79 | int res; 80 | for( c=0; c < OptListNum; c++ ){ 81 | if( *(OptList[c].optName) ){ 82 | 83 | res = OptNameCmp( line, OptList[c].optName, OptList[c].optType & CLA_CASE_INSENSITIVE ); 84 | 85 | if( res<0 ) 86 | continue; 87 | 88 | if( !(OptList[c].optType&type) ) 89 | continue; 90 | 91 | return c; 92 | 93 | } 94 | } 95 | 96 | return -1; 97 | 98 | } 99 | 100 | char* SplitLine( const char* line ){ 101 | 102 | char* return_string = NULL; 103 | int counter = 0; 104 | 105 | while( line[counter] && line[counter] != ';' ) 106 | counter++; 107 | 108 | return_string = malloc( counter + 1 ); 109 | 110 | if( counter ) 111 | memcpy( return_string, line, counter ); 112 | 113 | return_string[ counter ] = 0; 114 | 115 | return return_string; 116 | 117 | } 118 | 119 | int SetArguments( const char* line, claOptName_t* optN, claCfgItem_t* optV ){ 120 | /** parse line for arguments, option description passed in OptN, place for arguments passed in optV. 121 | 122 | return value: 123 | 124 | -1 - all ok 125 | -3 - not enough args 126 | -4 - too much args 127 | -5 - args not found 128 | -6 - incorrect value/type 129 | **/ 130 | 131 | 132 | 133 | int separators = 0; 134 | int arguments = 0; 135 | int c; 136 | int args_type = 0; 137 | char* argument = NULL; 138 | int arg_offset = 0; 139 | int j; 140 | int retcode = -1; 141 | 142 | for( c=0; line[c]; c++ ) 143 | if( line[c] == ';' ) 144 | separators++; 145 | 146 | if( !separators ) 147 | if( !*line ) 148 | return -5; 149 | 150 | arguments = separators + 1; 151 | 152 | args_type = optN->optType & ( CLA_TYPE_NUMBER | CLA_TYPE_STRING ); 153 | 154 | switch(args_type){ 155 | 156 | case CLA_TYPE_NUMBER: 157 | optV->nlist = realloc( optV->nlist, (optV->argNum+arguments) * sizeof(CLA_INT) ); 158 | assert( optV->nlist ); 159 | for( j = 0; j < arguments; j++ ) 160 | optV->nlist[ j + optV->argNum ] = 0; 161 | break; 162 | 163 | case CLA_TYPE_STRING: 164 | optV->slist = realloc( optV->slist, (optV->argNum+arguments) * sizeof(char*) ); 165 | assert(optV->slist); 166 | for(j=0;jslist[j+optV->argNum]=NULL; 168 | break; 169 | 170 | default: 171 | return -6; 172 | 173 | } 174 | 175 | for(c=0;cnlist[optV->argNum++] = atoll( argument ); 187 | free( argument ); 188 | break; 189 | case CLA_TYPE_STRING: 190 | optV->slist[optV->argNum++] = argument; 191 | break; 192 | default: 193 | free( argument ); 194 | 195 | } 196 | 197 | } 198 | optV->found++; 199 | optV->type = optN->optType; 200 | if(optV->argNumminAllowed) 201 | retcode = -3; 202 | if(optV->argNum>optN->maxAllowed && optN->maxAllowed) 203 | retcode = -4; 204 | 205 | return retcode; 206 | } 207 | 208 | 209 | int LineToOpt( claCfg_t* cfg,claOptName_t* opt, int optn, char* parse_line, int area ){ 210 | /*thesises: used ONLY for readCfg/ReadVarEnv.*/ 211 | /* retcode: 212 | -2 unknown option 213 | -3 not enough arguments for option 214 | -4 too many arguments 215 | -5 option requed argument 216 | -6 incorrect value 217 | -1 - success (!!!) 218 | >=0 - number of conflict option 219 | */ 220 | 221 | int ID; 222 | char* argument=NULL; 223 | int conflict_ID=-1; 224 | int paramflag=0; 225 | 226 | ID = GetOptionID( parse_line, opt, optn, area ); 227 | 228 | if( ID < 0 ) 229 | return -2; 230 | 231 | conflict_ID = claGroupOpt(cfg,opt[ID].optType & CLA_GROUP_ALL ); 232 | if( conflict_ID >= 0 && conflict_ID != ID ) /*confict found*/ 233 | return conflict_ID; 234 | 235 | if( opt[ID].ID != ID ){ 236 | printf(CLA_MSG_BAD_DECLARATION,opt[ID].optName); 237 | exit(-1); /*todo???*/ 238 | } 239 | 240 | cfg->item[ID].ID = opt[ID].ID; 241 | cfg->item[ID].type = opt[ID].optType; 242 | 243 | if(opt[ID].optType & CLA_TYPE_SWITCH){ 244 | cfg->item[ID].nlist=realloc(cfg->item[ID].nlist,sizeof(CLA_INT)); 245 | assert(cfg->item[ID].nlist); 246 | cfg->item[ID].nlist[0]++; 247 | cfg->item[ID].found++; 248 | return -1;/*ok*/ 249 | } 250 | 251 | argument = SkipEquiv( parse_line + strlen( opt[ID].optName ) ); 252 | return SetArguments( argument, &(opt[ID]), &(cfg->item[ID]) ) ; 253 | } 254 | -------------------------------------------------------------------------------- /src/colian/clatypes.h: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | * Section 1 * 4 | 5 | 6 | **/ 7 | 8 | 9 | 10 | /*integer data type for configuration items, int for int32, long long for int64*/ 11 | #define CLA_INT long long 12 | 13 | /*fuction to convert string to integer, atoi for int32, atoll for int64 */ 14 | #define CLA_INTC atoll 15 | 16 | 17 | 18 | /** 19 | This structure represent a option name, description and type. 20 | Array of thouse structures requed by mostly all functions of library 21 | **/ 22 | typedef struct { 23 | int ID; /** Number of option,must be unique for application 24 | Strongly recommended to set ID equal to order 25 | number of option for enabling fast mode **/ 26 | char* optName; /** Name of option in text config and --long options 27 | in command line **/ 28 | char optLetter; /** Short name of option (used only in command line)*/ 29 | int optType; /** Type of the option (see option types) **/ 30 | int minAllowed; /** Minimal allowed number of arguments, 31 | (0 means no requied arguments)*/ 32 | int maxAllowed; /** Maximal allowed number of argumbents 33 | (zero means no limitation for number of arguments) 34 | **/ 35 | char* description;/** Text description of option, used in --help, 36 | in WriteTextConfig for user info only*/ 37 | }claOptName_t; 38 | 39 | 40 | 41 | /** This structure describe a value(s) of found option. **/ 42 | typedef struct{ 43 | int found; /** Flag, displaying, that option has been found **/ 44 | int ID; /** ID (copying from claOptName_t) **/ 45 | int type; /** Type, (see option types) **/ 46 | int argNum; /** number of found arguments for option **/ 47 | union{ /** usage of nlist or slist depends on type **/ 48 | CLA_INT* nlist; /** array of numeric values of arguments **/ 49 | char** slist; /** array of string values of argumnets **/ 50 | }; 51 | }claCfgItem_t; 52 | 53 | 54 | /** 55 | This structure contain a list (array) of found options and additional 56 | data for readed config/command line. Common used for mostly all function 57 | (as input or output value) 58 | **/ 59 | typedef struct{ 60 | int entryNum; /** number of enties (must be equal to number 61 | of option in array of claOptName_t) **/ 62 | claCfgItem_t *item; /** pointer to array of values of arguments */ 63 | int FreeOptNum; /** number of 'FreeOptions' (only for command 64 | line **/ 65 | char** FreeOpt; /** Pointer to array of Free Options, number 66 | of entries equal to FreeOptNum **/ 67 | }claCfg_t; 68 | 69 | 70 | 71 | /** 72 | 73 | * Section 2 * 74 | 75 | Data types 76 | 77 | Note: all values in this section are bitflags 78 | for fields optType in claOptName_t and type in claCfgItem_t. 79 | 80 | **/ 81 | 82 | 83 | 84 | enum { /*basic data types*/ 85 | CLA_TYPE_NUMBER=1, /** number (signed int 32) */ 86 | CLA_TYPE_SWITCH=2, /** switch - boolean flag (0 or 1) */ 87 | CLA_TYPE_STRING=4 /** string */ 88 | }; 89 | 90 | enum{/* area of using option*/ 91 | CLA_CMD=0x100, /** command line **/ 92 | CLA_CFG=0x200, /** config file **/ 93 | CLA_ENV=0x400 /** environment variable **/ 94 | }; 95 | 96 | 97 | #define CLA_GROUP_0 0x00010000 98 | #define CLA_GROUP_1 0x00020000 99 | #define CLA_GROUP_2 0x00040000 100 | #define CLA_GROUP_3 0x00080000 101 | #define CLA_GROUP_4 0x00100000 102 | #define CLA_GROUP_5 0x00200000 103 | #define CLA_GROUP_6 0x00400000 104 | #define CLA_GROUP_7 0x00800000 105 | #define CLA_GROUP_8 0x01000000 106 | #define CLA_GROUP_9 0x02000000 107 | #define CLA_GROUP_A 0x04000000 108 | #define CLA_GROUP_B 0x08000000 109 | #define CLA_GROUP_C 0x10000000 110 | #define CLA_GROUP_D 0x20000000 111 | #define CLA_GROUP_E 0x40000000 112 | 113 | #define CLA_GROUP_ALL (CLA_GROUP_0|CLA_GROUP_1|CLA_GROUP_2|CLA_GROUP_3|CLA_GROUP_4|CLA_GROUP_5|CLA_GROUP_6|CLA_GROUP_7|CLA_GROUP_8|CLA_GROUP_9|CLA_GROUP_A|CLA_GROUP_B|CLA_GROUP_C|CLA_GROUP_D|CLA_GROUP_E) 114 | 115 | #define CLA_ALL (CLA_CMD|CLA_CFG|CLA_ENV) 116 | /** all possible areas of using **/ 117 | 118 | 119 | #define CLA_CASE_INSENSITIVE 0x20 120 | /*ignore case for option name*/ 121 | 122 | #define CLA_HELP (CLA_TYPE_SWITCH|CLA_CMD|CLA_EXCLUSIVE) 123 | /** default set of option for --help and --ver options **/ 124 | 125 | #define CLA_NUMBER (CLA_TYPE_NUMBER|CLA_ALL) 126 | /**standart for number, accepting from any source **/ 127 | 128 | #define CLA_SWITCH (CLA_TYPE_SWITCH|CLA_ALL) 129 | /**standart for switch, accepting from any source **/ 130 | 131 | #define CLA_STRING (CLA_TYPE_STRING|CLA_ALL) 132 | /**standart for string, accepting from any source **/ 133 | 134 | #define CLA_EXCLUSIVE 0x10 135 | /** 136 | Exclusive flag (actual only for command line parsing, 137 | stop checking for minimal number of FreeOptions in 138 | claParseCommandLine. (used for --help, --version, etc. 139 | **/ 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /src/colian/cmd.c: -------------------------------------------------------------------------------- 1 | #include "colian.h" 2 | #include "internal.h" 3 | 4 | int GetOptionID_short(const char letter,claOptName_t* OptList,const int OptListNum){ 5 | /*return a ID of option (by short name), or -1 if option not found*/ 6 | int c; 7 | 8 | for( c = 0; c < OptListNum; c++ ) 9 | if( OptList[c].optLetter == letter && ( OptList[c].optType & CLA_CMD ) ) 10 | return c; 11 | 12 | return -1; 13 | } 14 | 15 | 16 | static void SetFreeOpt (claCfg_t* cfg, char* line){ 17 | cfg->FreeOptNum++; 18 | cfg->FreeOpt = realloc( cfg->FreeOpt, cfg->FreeOptNum * sizeof(char*) ); 19 | assert( cfg->FreeOpt ); 20 | cfg->FreeOpt[cfg->FreeOptNum - 1] = line; 21 | } 22 | 23 | 24 | claCfg_t* claParseCommandLine( 25 | int argc, char* argv[], claOptName_t* OptList, int OptListNum, 26 | int MinFreeNum, int MaxFreeNum, int Ctrl 27 | ){ 28 | 29 | claCfg_t* retval = claInit(OptListNum,MaxFreeNum); 30 | 31 | int c = 0; 32 | int j = 0; 33 | 34 | int args_left = 0; /*number of arguments to parse*/ 35 | int ID = -1; 36 | int conflict_ID = -1; 37 | int result_code = 0; 38 | int silence_flag= Ctrl & CLA_FLAG_SILENCE; 39 | 40 | assert( retval ); 41 | 42 | for( c = 1; c < argc; c++ ){ 43 | 44 | 45 | if(args_left > 0){/*pickup leftover arguments for option*/ 46 | if( ID < 0 ){ 47 | if( !silence_flag ) 48 | printf(CLA_MSG_CMD_INTERNAL_ERROR_1); 49 | claClose(retval); 50 | return NULL; 51 | } 52 | args_left=0; 53 | result_code = SetArguments( argv[c], &( OptList[ID] ), &( retval->item[ID] ) ); 54 | switch( result_code ){ 55 | case -1: /*ok*/ 56 | continue; 57 | case -3: /*not enough*/ 58 | args_left = 1; 59 | continue; 60 | case -4: /*too much*/ 61 | if( !silence_flag ) 62 | printf( CLA_MSG_CMD_TOO_MUCH_SL,OptList[ID].optName, OptList[ID].optLetter); 63 | if(Ctrl&CLA_FLAG_STOP_TOO_MUCH){ 64 | claClose(retval); 65 | return NULL; 66 | } 67 | continue; 68 | case -5:/*argument not found - impossible here (i.e. argv[c] can not be empty string) */ 69 | continue; 70 | case -6: /*invalid argument(s) type*/ 71 | if(!silence_flag) 72 | printf(CLA_MSG_CMD_INCORRECT_ARG_SL,OptList[ID].optName, OptList[ID].optLetter, argv[c]); 73 | if( Ctrl & CLA_FLAG_STOP_INCORRECT_ARG ){ 74 | claClose(retval); 75 | return NULL; 76 | } 77 | } 78 | continue; 79 | } 80 | 81 | 82 | if(argv[c][0]=='-'){ 83 | 84 | if( !argv[c][1] ){ /* single '-' is a Free Option */ 85 | SetFreeOpt( retval, "-" ); 86 | continue; 87 | } 88 | 89 | if(argv[c][1]=='-'){ 90 | 91 | if(!argv[c][2]){/*stop mode, all other options should be accepted as free option*/ 92 | for( j = c+1 ; j < argc ; j++ ) 93 | SetFreeOpt( retval, argv[j] ); 94 | break; 95 | } 96 | 97 | /*long option*/ 98 | 99 | result_code = LineToOpt(retval,OptList, OptListNum, argv[c]+2, CLA_CMD ); 100 | if(result_code >= 0){ 101 | if(!silence_flag) 102 | printf(CLA_MSG_CMD_CONFLICT_L,argv[c]+2,OptList[result_code].optName); 103 | if( Ctrl & CLA_FLAG_STOP_CONFLICT ){ 104 | claClose(retval); 105 | return NULL; 106 | } 107 | } 108 | if(result_code < -1){/*result_code==-1 ok (skip). result_code < -1 errors*/ 109 | switch(result_code){ 110 | case -2: /*unknown*/ 111 | if( !silence_flag ) 112 | printf( CLA_MSG_CMD_UNKNOWN_L, argv[c]+2 ); 113 | if( Ctrl & CLA_FLAG_STOP_UNKNOWN ){ 114 | claClose( retval ); 115 | return NULL; 116 | } 117 | continue; 118 | case -3: 119 | /*passtrough*/ 120 | case -5:/*not enough, not error, continue parsing in upper section */ 121 | 122 | ID = GetOptionID( argv[c] + 2, OptList, OptListNum, CLA_CMD ); 123 | args_left = 1; 124 | continue; 125 | case -4:/*too much*/ 126 | if( !silence_flag ) 127 | printf( CLA_MSG_CMD_TOO_MUCH_L, argv[c] + 2 ); 128 | if( Ctrl & CLA_FLAG_STOP_TOO_MUCH ){ 129 | claClose( retval ); 130 | return NULL; 131 | } 132 | continue; 133 | case -6: /*invalid argument type*/ 134 | if( !silence_flag ) 135 | printf( CLA_MSG_CMD_INCORRECT_ARGS_L, argv[c] + 2); 136 | if( Ctrl & CLA_FLAG_STOP_INCORRECT_ARG ){ 137 | claClose( retval ); 138 | return NULL; 139 | } 140 | } 141 | } 142 | ID=-1; 143 | args_left = 0; 144 | continue; 145 | } 146 | 147 | /*short options*/ 148 | for( j = 1; argv[c][j] && j; j++ ){ 149 | 150 | ID = GetOptionID_short( argv[c][j], OptList, OptListNum ); 151 | 152 | if( ID < 0 ){/*unknown option*/ 153 | if( !silence_flag ) 154 | printf(CLA_MSG_CMD_UNKNOWN_S, argv[c][j] ); 155 | if( Ctrl & CLA_FLAG_STOP_UNKNOWN ){ 156 | claClose( retval ); 157 | return NULL; 158 | } 159 | continue; 160 | } 161 | 162 | if( OptList[ID].ID != ID ){ 163 | printf(CLA_MSG_BAD_DECLARATION, OptList[ID].optName ); 164 | exit(-1); 165 | } 166 | 167 | conflict_ID = claGroupOpt( retval, OptList[ID].optType & CLA_GROUP_ALL ); 168 | if( conflict_ID >= 0 && conflict_ID != ID ){ 169 | if( !silence_flag ) 170 | printf( CLA_MSG_CMD_CONFLICT_S, argv[c][j], OptList[conflict_ID].optLetter ); 171 | if( Ctrl & CLA_FLAG_STOP_CONFLICT ){ 172 | claClose( retval ); 173 | return NULL; 174 | } 175 | if(argv[c][j+1]==':'||argv[c][j+1]=='=') /*if -O=something, stop parsing*/ 176 | j=-1; 177 | continue; 178 | } 179 | 180 | if(argv[c][j+1]=='='||argv[c][j+1]==':'){/*found argument(s) for shot option*/ 181 | 182 | result_code = SetArguments(argv[c]+j+2, &(OptList[ID]), &(retval->item[ID])); 183 | 184 | switch( result_code){ 185 | 186 | case -1: /*ok*/ 187 | retval->item[ID].type=OptList[ID].optType; 188 | retval->item[ID].found++; 189 | args_left = 0; 190 | ID = -1; 191 | break; 192 | case -3: /*not enough, not error, just continue in upper section*/ 193 | retval->item[ID].type=OptList[ID].optType; 194 | retval->item[ID].found++; 195 | args_left = 1; 196 | break; 197 | case -4:/*too much*/ 198 | if( !silence_flag ) 199 | printf( CLA_MSG_CMD_TOO_MUCH_S, argv[c][j] ); 200 | if( Ctrl & CLA_FLAG_STOP_TOO_MUCH ){ 201 | claClose( retval ); 202 | return NULL; 203 | } 204 | break; 205 | case -5: /*not found*/ 206 | if( !silence_flag ) 207 | printf( CLA_MSG_CMD_ARG_NOT_FOUND_S, argv[c][j] ); 208 | if( Ctrl & CLA_FLAG_STOP_UNKNOWN ){ 209 | claClose( retval ); 210 | return NULL; 211 | } 212 | break; 213 | case -6:/*invalid type*/ 214 | if( !silence_flag) 215 | printf( CLA_MSG_CMD_INCORRECT_S, argv[c][j] ); 216 | if( Ctrl & CLA_FLAG_STOP_INCORRECT_ARG ){ 217 | claClose( retval ); 218 | return NULL; 219 | } 220 | break; 221 | } 222 | break; 223 | 224 | }else{/*option without '='*/ 225 | if( OptList[ID].optType & CLA_TYPE_SWITCH ){ 226 | retval->item[ID].argNum++; 227 | retval->item[ID].nlist = realloc (retval->item[ID].nlist,retval->item[ID].argNum * sizeof(retval->item[ID].nlist[0]) ); 228 | assert( retval->item[ID].nlist ); 229 | retval->item[ID].nlist [retval->item[ID].argNum-1]++; 230 | retval->item[ID].type = OptList[ID].optType; 231 | retval->item[ID].found++; 232 | continue; 233 | } 234 | if(!OptList[ID].minAllowed){ 235 | retval->item[ID].found++; 236 | retval->item[ID].type=OptList[ID].optType; 237 | retval->item[ID].argNum=1; 238 | if(OptList[ID].optType & CLA_TYPE_STRING){ 239 | retval->item[ID].slist=malloc(sizeof(char*)); 240 | assert(retval->item[ID].slist); 241 | retval->item[ID].slist[0]=strdup(""); 242 | assert(retval->item[ID].slist[0]); 243 | } 244 | if(OptList[ID].optType & CLA_TYPE_NUMBER){ 245 | retval->item[ID].nlist=malloc(sizeof(CLA_INT)); 246 | assert(retval->item[ID].nlist); 247 | retval->item[ID].slist[0]=0; 248 | } 249 | continue; 250 | } 251 | if( !argv[c][j+1] ){ /*ok, continue argument parsing*/ 252 | args_left =1; 253 | break; 254 | }else{ /*error*/ /*TODO args accepting?*/ 255 | if( !silence_flag) 256 | printf(CLA_MSG_CMD_ARGS_REQUED_S,argv[c][j]); 257 | if( Ctrl & CLA_FLAG_STOP_NOT_ENOUGH ){ 258 | claClose( retval ); 259 | return NULL; 260 | } 261 | } 262 | } 263 | } 264 | continue; 265 | } 266 | /*free opt*/ 267 | SetFreeOpt( retval, argv[c] ); 268 | } 269 | if(args_left && ID>=0){ 270 | if(!silence_flag) 271 | printf(CLA_MSG_CMD_NOT_ENOUGH_FREE,OptList[ID].optName, OptList[ID].optLetter); 272 | if(Ctrl&CLA_FLAG_STOP_NOT_ENOUGH){ 273 | claClose(retval); 274 | return NULL; 275 | } 276 | } 277 | 278 | return retval; 279 | } 280 | -------------------------------------------------------------------------------- /src/colian/colian.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_COLIAN_H 2 | #define _H_COLIAN_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "clatypes.h" 10 | #include "i18n.h" 11 | 12 | /** 13 | 14 | * Section 3 * 15 | 16 | Function prototypes 17 | 18 | **/ 19 | 20 | 21 | /** 22 | This function parse command line and return structure with parsed values. 23 | It returns pointer to structure if parsing successfull, return NULL otherwise. 24 | 25 | See also: macross ParseCommandLine 26 | 27 | Note: returned value should be passed to claJoin() or closed by claClose() 28 | after use to avoid memory leak 29 | 30 | **/ 31 | claCfg_t* claParseCommandLine( 32 | int argc, /** Number of application arguments in 33 | command line **/ 34 | char* argv[], /** Array of pointers to arguments **/ 35 | claOptName_t* OptList, /** array of application options **/ 36 | int OptListNum, /** Number of entries in OptList **/ 37 | int MinFreeNum, /** minimal requed number of FreeOptions, 38 | (inoring, if option with CLA_EXCLUSIVE 39 | flag happens in arguments **/ 40 | int MaxFreeNum, /** Maximal allowed number of FreeOptions **/ 41 | int Ctrl /** Bitfield for different behavior, 42 | see section 4 for possible values **/ 43 | ); 44 | 45 | 46 | 47 | /** 48 | This function parse text configuration file and return structure with parsed 49 | values. It returns pointer to structure if parsing successfull, return NULL 50 | otherwise. 51 | 52 | See also: macross ReadTextConfig 53 | 54 | Note: returned value should be passed to claJoin() or closed by claClose() 55 | after use to avoid memory leak 56 | 57 | Note3: This function allow to use keyword 'include' in configuration file, 58 | but check for self-reccurent call is very limited, so, for stability, disable 59 | include keyword by CLA_FLAG_DISABLE_INCLUDE bit in Ctrl bitfield. 60 | 61 | **/ 62 | claCfg_t* claReadTextConfig( 63 | const char* FileName, /** File name. Must be absolute or 64 | relative path **/ 65 | claOptName_t* OptList, /** aray of apliation options **/ 66 | int OptListNum, /** Number of entries in OptList **/ 67 | int Ctrl /** Bitfield for different behavior, 68 | see section 4 for possible values **/ 69 | ); 70 | 71 | 72 | /** 73 | This function join two configuration in one (them both MUST have a one 74 | (or identical) OptList! ). Result configuration contain values from 75 | both incoming configuration, in case of conflict, selecting depends on 76 | priority1 and priority2. 77 | 78 | Complete list of behavior (if no groups defined, else see notes): 79 | 80 | for each entry in both incoming configuration (config1, config2): 81 | 82 | if no active value in config1, config2, result has no active value. 83 | if only one from config1, config2 has active value, result equal to 84 | it. 85 | if both config1 and config2 has active values, result depend on 86 | priority1 and priority2: 87 | if priority1 >= priority2, result equal to value from config1 88 | if priority2 < priirity2, result equal to value from config2. 89 | 90 | 91 | Note1: after join you should not use config1 or config2 values, becouse 92 | claJoin clear 'em both 93 | 94 | Note: returned value should be passed to claJoin() or closed by claClose() 95 | after use to avoid memory leak 96 | 97 | Note: 98 | some options from configuration with lower priority can be not 99 | included to target configuration due group conflict with existing 100 | options in configuration with higher priority. 101 | **/ 102 | 103 | claCfg_t* claJoin( 104 | claCfg_t* config1, /** Fist config **/ 105 | claCfg_t* config2, /** Second config **/ 106 | int Priority1, /** Priority of first config **/ 107 | int Priority2 /** Priority of second config **/ 108 | ); 109 | 110 | 111 | /** 112 | This function write configuration to text file. 113 | By default writing only active options with CLA_CFG flag 114 | (can be changed by CLA_FLAGS_* via Ctrl, see Section 4) 115 | 116 | return value: 117 | 1 success 118 | -1 write fail due i/o error (error code keeps in errorlevel) 119 | 0 error in configuration 120 | 121 | **/ 122 | int claWriteTextConfig( 123 | claCfg_t* cfg, /** configuration for writing, must match OptList **/ 124 | const char* FileName, /** Filename of file (if file exist, it will be replaced **/ 125 | claOptName_t* OptList, /** List of option name **/ 126 | int OptListNum, /** number of entries of OptList **/ 127 | int Ctrl /** Control flags, see section 4 for possible values **/ 128 | ); 129 | 130 | 131 | /** 132 | Close configuration, free all allocated memory. 133 | Can cause undefined behavior, if config used after 134 | calling claClose or some of config data has been 135 | freed before call. 136 | return value: none 137 | **/ 138 | void claClose(claCfg_t* config); 139 | 140 | 141 | /** 142 | print to specified file (or stdin/stderr) list of option(s) from OptList, 143 | with description. 144 | printed option must have flag CLA_CMD (all others ignoring) 145 | 146 | return value: 147 | -1 - i/o error (error code keeps in errorlevel) 148 | 0 - success 149 | **/ 150 | 151 | void claPrintOpt( 152 | claOptName_t* OptList, 153 | int OptListN, 154 | FILE* to 155 | ); 156 | 157 | 158 | /** 159 | Search for any option with specified in group_mask group(s), 160 | (two or more groups can be combined with '|') 161 | return value: 162 | -1 if nothing is found, 163 | order number of found option 164 | **/ 165 | 166 | int claGroupOpt( claCfg_t* config, int group_mask ); 167 | 168 | 169 | 170 | 171 | /** those function used by macrosses sopt(M) nopt(M) below **/ 172 | 173 | 174 | /** debug print of options **/ 175 | void dbg_print_cfg( 176 | FILE* f, 177 | claOptName_t* optlist, 178 | claCfg_t* cfg 179 | ); 180 | 181 | claCfg_t* claReadEnvironment( char **envp,claOptName_t* option, int option_number,int Ctrl ); 182 | 183 | 184 | 185 | /** This macross used instead claParseCommandLine to reduce number of arguments, 186 | instead OptList/OptListNum it accept a single option OptList, wich one MUST 187 | BE A ARRAY claOptName_t[]. 188 | **/ 189 | #define ParseCommandLine(argc, argv, OptList, MinFreeNum, MaxFreeNum, Error) \ 190 | claParseCommandLine(argc,argv,OptList,sizeof(OptList)/sizeof(OptList[0]),MinFreeNum,MaxFreeNum,Error) 191 | 192 | 193 | /** This macross used instead claReadTextConfig to reduce number of arguments, 194 | instead OptList/OptListNum it accept a single option OptList, wich one MUST 195 | BE A ARRAY claOptName_t[]. 196 | **/ 197 | #define ReadTextConfig(name, OptList, Ctrl) \ 198 | claReadTextConfig(name, OptList, sizeof(OptList)/sizeof(OptList[0]), Ctrl ) 199 | 200 | /** This macross used instead claWriteTextConfig to reduce number of arguments, 201 | instead OptList/OptListNum it accept a single option OptList, wich one MUST 202 | BE A ARRAY claOptName_t[]. 203 | **/ 204 | #define WriteTextConfig(cfg,FileName,opt,Ctrl) \ 205 | claWriteTextConfig(cfg,FileName, opt, sizeof(opt)/sizeof(opt[0]), Ctrl ) 206 | 207 | 208 | #define ReadEnvironment(envp,option,Ctrl) \ 209 | claReadEnvironment(envp,option,sizeof(option)/sizeof(option[0]),Ctrl) 210 | 211 | /** This macross used instead claPrintOpt to reduce number of arguments, 212 | instead OptList/OptListNum it accept a single option OptList, wich one MUST 213 | BE A ARRAY claOptName_t[]. 214 | **/ 215 | #define PrintOpt(optlist,to) \ 216 | claPrintOpt(optlist,sizeof(optlist)/sizeof(optlist[0]),to) 217 | 218 | 219 | /** this macross return a number of Free Option**/ 220 | #define freeoptnum(cfg) (cfg->FreeOptNum) 221 | 222 | /** This macross return specified Free Option **/ 223 | #define freeopt(cfg,OptN) (OptN < cfg->FreeOptNum ? cfg->FreeOpt[OptN] : "") 224 | 225 | 226 | 227 | 228 | 229 | /** 230 | nopt(cfg,ID) is a macross, returns value of the first numeric argument of 231 | the option with specified ID from specified configuration cfg, or 232 | return 0 if option not found or non active. (and 0 can be returned as 233 | valid value of active option). 234 | Macross MUST be called with valid cfg structure. 235 | **/ 236 | #define nopt(cfg,ID) \ 237 | (IDentryNum?( cfg->item[ID].found ? cfg->item[ID].nlist[0] : 0 ):0) 238 | 239 | 240 | /** 241 | sopt(cfg,ID) is a macross, returns pointer to the first string argument of 242 | the option with specified ID from specified configuration cfg, or 243 | return NULL if option not found or non active. (NULL never returns for 244 | valid active option). 245 | Macross MUST be called with valid cfg structure. 246 | **/ 247 | #define sopt(cfg,ID) \ 248 | (IDentryNum?( cfg->item[ID].found ? cfg->item[ID].slist[0] : ""):"") 249 | #define stropt(cfg,ID) 250 | 251 | 252 | 253 | /** 254 | noptM(cfg,ID,order) is a macross, returns numeric value of the specifed by 255 | order numeric argument of the option with specified ID from specified 256 | configuration cfg, or return 0 if option not found or non active. 257 | (and 0 can be returned as valid value of active option). 258 | Macross MUST be called with valid cfg structure. 259 | **/ 260 | #define noptM(cfg,ID,order)\ 261 | (IDentryNum?(\ 262 | cfg->item[ID].found ? (\ 263 | order < cfg->item[ID].argNum?cfg->item[ID].nlist[order] : 0 \ 264 | ):0 \ 265 | ):0) 266 | 267 | 268 | /** 269 | noptM(cfg,ID,order) is a macross, returns string value of the specifed 270 | by order numeric argument of the option with specified ID from specified 271 | configuration cfg, or return NUKK if option not found or non active. 272 | (NULL never returns for valid active option). 273 | Macross MUST be called with valid cfg structure. 274 | **/ 275 | #define soptM(cfg,ID,order)\ 276 | (IDentryNum?(\ 277 | cfg->item[ID].found ? (\ 278 | order < cfg->item[ID].argNum?cfg->item[ID].slist[order] : ""\ 279 | ):"" \ 280 | ):"" ) 281 | 282 | /** 283 | claOptNumber return number of arguments for specified by ID option 284 | from specified configuration cfg or return 0 if option not found 285 | **/ 286 | #define argnum( cfg, ID ) \ 287 | (IDentryNum?(cfg->item[ID].found?cfg->item[ID].argNum:0):0) 288 | 289 | 290 | 291 | #define isactive( cfg, ID ) \ 292 | (IDentryNum?(cfg->item[ID].found):0) 293 | 294 | /** 295 | 296 | * Section 4 * 297 | 298 | Flags for Ctrl control bitfield 299 | 300 | Note: all those values are using for control function via Ctrl parameter. 301 | 302 | **/ 303 | 304 | 305 | 306 | #define CLA_FLAG_STOP_UNKNOWN 0x2 307 | /** Stop parsing if unknown option found, function 308 | will return a fail (NULL) 309 | Applicable to: 310 | claParseCommandLine 311 | claReadTextConfig 312 | **/ 313 | 314 | #define CLA_FLAG_STOP_NOT_ENOUGH 0x4 315 | /** Stop parsing, if no enough arguments for option found 316 | Applicable to: 317 | claParseCommandLine 318 | claReadTextConfig 319 | **/ 320 | 321 | #define CLA_FLAG_STOP_TOO_MUCH 0x8 322 | /** Stop parsing if too much arguments has been specified 323 | Applicable to: 324 | claParseCommandLine 325 | claReadTextConfig 326 | **/ 327 | 328 | #define CLA_FLAG_SILENCE 0x10 329 | /** Do not report anything to user (do not print anything to screen) 330 | Applicable to: 331 | claParseCommandLine 332 | claReadTextConfig 333 | claWriteTextConfig 334 | **/ 335 | 336 | #define CLA_FLAG_STOP_INCORRECT_ARG 0x20 337 | /** Stop parsing if incorrect type of argument (e.g. string instead number) 338 | Applicable to: 339 | claParseCommandLine 340 | claReadTextConfig 341 | claReadEnvironmentVar 342 | **/ 343 | 344 | 345 | #define CLA_FLAG_STOP_CONFLICT 0x40 346 | 347 | 348 | #define CLA_FLAG_STOP_OPTION_REQUED 0x80 349 | 350 | #define CLA_FLAG_STOP_ALL_ERRORS (CLA_FLAG_STOP_UNKNOWN|CLA_FLAG_STOP_NOT_ENOUGH|CLA_FLAG_STOP_TOO_MUCH|CLA_FLAG_STOP_INCORRECT_ARG|CLA_FLAG_STOP_CONFLICT|CLA_FLAG_STOP_OPTION_REQUED) 351 | 352 | #define CLA_FLAG_ENABLE_INCLUDE 0x1000000 353 | /** Allow use keyword 'include', without this options including files 354 | will be ignored, and line with include will be parsed as 355 | common line (and cause an error), 356 | Applicable only to claReadTextConfig. 357 | **/ 358 | 359 | 360 | #define CLA_FLAG_SAVE_ALL 0x1000000 361 | /** Save all active options, regardless CLA_CFG bit for optType(type). 362 | Applicable only to claWriteTextConfig 363 | **/ 364 | 365 | #define CLA_FLAG_IGNORE_NONSAVABLE 0x2000000 366 | /** Do not report about active option without CLA_CFG flag 367 | Applicable only to claWriteTextConfig 368 | **/ 369 | 370 | #define CLA_FLAG_STOP_NONSAVABLE 0x4000000 371 | /** Stop saving if found active option withou CLA_CFG flag 372 | Applicable only to claWriteTextConfig 373 | **/ 374 | 375 | 376 | #define CLA_FLAG_OPT_COMMENT 0x8000000 377 | /** Add a comment line under saved option with description 378 | (generating from option list) 379 | Applicable only to claWriteTextConfig 380 | **/ 381 | 382 | #define CLA_FLAG_SAVE_NOTFOUND 0x10000000 383 | /** Save non active options as commented line 384 | Applicable only to claWriteTextConfig 385 | **/ 386 | 387 | #define CLA_FLAG_HEAD_INFO 0x20000000 388 | /** Create a simple file header with description of 389 | synthax of the file (CLA_MSG_TEXT_CONFIG_HEAD used) 390 | Applicable only to claWriteTextConfig 391 | **/ 392 | 393 | 394 | #define CLA_FLAG_NO_FLAGS 0x0 395 | /** used only for mnemonic purposes, instead 0*/ 396 | 397 | 398 | /** Debug text **/ 399 | 400 | #define CLA_MSG_DBG_BODY "--%s (type=0x%X,%d), value=" 401 | #define CLA_MSG_DBG_FREEOPT_HEAD "Free Opt List (%d)\n" 402 | 403 | 404 | 405 | /** include keyword **/ 406 | #define CLA_KEYWORD_INCLUDE "include" 407 | 408 | 409 | #endif 410 | -------------------------------------------------------------------------------- /src/colian/dbg.c: -------------------------------------------------------------------------------- 1 | #include "colian.h" 2 | #include "internal.h" 3 | 4 | void dbg_print_cfg( FILE* f, claOptName_t* optlist, claCfg_t* cfg ){ 5 | 6 | int c,j; 7 | 8 | if( !f && !cfg ) 9 | return; 10 | for( c=0; c < cfg->entryNum; c++ ){ 11 | if( cfg->item[c].found ){ 12 | 13 | fprintf( 14 | f, 15 | CLA_MSG_DBG_BODY, 16 | optlist[c].optName, 17 | optlist[c].optType, 18 | optlist[c].optType & 0xF 19 | ); 20 | for( j=0; j < cfg->item[c].argNum; j++ ){ 21 | if( optlist[c].optType & CLA_TYPE_STRING ) 22 | fprintf( f, "%s ", cfg->item[c].slist[j] ); 23 | else 24 | fprintf( f, "%d ", cfg->item[c].nlist[j] ); 25 | } 26 | 27 | fprintf( f, "\n" ); 28 | 29 | } 30 | } 31 | 32 | if( cfg->FreeOptNum ){ 33 | 34 | fprintf( f, CLA_MSG_DBG_FREEOPT_HEAD, cfg->FreeOptNum ); 35 | for( c = 0; c < cfg->FreeOptNum; c++ ) 36 | fprintf( f, "%d = %s\n", c + 1, cfg->FreeOpt[c] ); 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/colian/env.c: -------------------------------------------------------------------------------- 1 | #include "colian.h" 2 | #include "internal.h" 3 | 4 | claCfg_t* claReadEnvironment( char **envp,claOptName_t* option, int option_number,int Ctrl ){ 5 | 6 | claCfg_t* retval = claInit ( option_number,0); 7 | int ec = 0; 8 | int silence_flag = Ctrl & CLA_FLAG_SILENCE; 9 | int result_code = 0; 10 | 11 | struct { 12 | int flag; char* msg; 13 | }env_error_act[]={ 14 | { 0, NULL }, /*skip*/ 15 | { 0, NULL }, /*skip*/ 16 | { 0, 0 }, /*skip*/ 17 | { CLA_FLAG_STOP_NOT_ENOUGH, CLA_MSG_ENV_NO_ENOUGH_ARGS }, /*not enough arguments*/ 18 | { CLA_FLAG_STOP_TOO_MUCH, CLA_MSG_ENV_TOO_MUCH_ARGS }, /*too many arguments*/ 19 | { CLA_FLAG_STOP_OPTION_REQUED, CLA_MSG_ENV_OPTION_REQUED }, /*no eny arguments found*/ 20 | { CLA_FLAG_STOP_INCORRECT_ARG, CLA_MSG_ENV_INCORRECT_ARG }, /*incorrect argument type*/ 21 | }; 22 | 23 | 24 | 25 | for(ec=0;envp[ec];ec++){ 26 | 27 | result_code = LineToOpt( retval, option, option_number, envp[ec], CLA_ENV ); 28 | if( result_code >= 0 ){/*error handling, conflict option*/ 29 | if(! silence_flag) 30 | printf(CLA_MSG_ENV_CONFLICT, envp[ec], option[result_code].optName ); 31 | if( Ctrl & CLA_FLAG_STOP_CONFLICT ){ 32 | claClose( retval ); 33 | return NULL; 34 | } 35 | continue; 36 | } 37 | 38 | 39 | if( result_code == -1 ) 40 | continue; /*unknown options in environment just ignoring*/ 41 | 42 | if( result_code < -2 ){/*error handling etc*/ 43 | assert( result_code >= -6 ); 44 | if( !silence_flag ) 45 | printf( env_error_act[ 0 - result_code ].msg, envp[ec]); 46 | if(Ctrl & env_error_act[ 0 - result_code ].flag ){ 47 | claClose( retval ); 48 | return NULL; 49 | } 50 | continue; 51 | } 52 | } 53 | return retval; 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/colian/group.c: -------------------------------------------------------------------------------- 1 | #include "colian.h" 2 | #include "internal.h" 3 | 4 | /** Search for any option with specified in group_mask group(s), 5 | (two or more groups can be combined with '|')**/ 6 | 7 | /**return value: -1 if nothing is found, or order number of found option**/ 8 | 9 | int claGroupOpt( claCfg_t* config, int group_mask ){ 10 | 11 | int c; 12 | 13 | if( group_mask ) 14 | for( c = 0; c < config->entryNum; c++ ) 15 | if( config->item[c].found && ( config->item[c].type & group_mask ) ) 16 | return c; 17 | 18 | return -1; 19 | 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/colian/i18n.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_CLA_I18N_H 2 | #define _H_CLA_I18N_H 3 | 4 | #define CLA_MSG_BAD_DECLARATION "Declaration is invalid (option %s's ID != order number in declaration)\n" 5 | 6 | #define CLA_MSG_CMD_INTERNAL_ERROR_1 "internal error (claParseCommandLine): ID<0\n" 7 | #define CLA_MSG_CMD_TOO_MUCH_SL "option --%s (-%c) - too many arguments\n" 8 | #define CLA_MSG_CMD_INCORRECT_ARG_SL "option --%s (-%c): argument \"%s\" is not valid\n" 9 | #define CLA_MSG_CMD_CONFLICT_L "option --%s should not be used together with --%s\n" 10 | #define CLA_MSG_CMD_UNKNOWN_L "option --%s is not recognized\n" 11 | #define CLA_MSG_CMD_TOO_MUCH_L "option --%s - too many arguments\n" 12 | #define CLA_MSG_CMD_NO_ARGS_L "option --%s requed argument\n" 13 | #define CLA_MSG_CMD_INCORRECT_ARGS_L "option --%s - incorrect argument type\n" 14 | #define CLA_MSG_CMD_UNKNOWN_S "option -%c is not recognized\n" 15 | #define CLA_MSG_CMD_CONFLICT_S "option -%c should not used together with -%c\n" 16 | #define CLA_MSG_CMD_TOO_MUCH_S "option -%c - too many arguments\n" 17 | #define CLA_MSG_CMD_ARG_NOT_FOUND_S "option -%c requed argument\n" 18 | #define CLA_MSG_CMD_INCORRECT_S "option -%c - incorrect argument type\n" 19 | #define CLA_MSG_CMD_ARGS_REQUED_S "option -%c requed argument\n" 20 | #define CLA_MSG_CMD_NOT_ENOUGH_FREE "not enough arguments\n" 21 | 22 | #define CLA_MSG_OPTION_CONFLICT "%s should not be used together with %s\n" 23 | #define CLA_MSG_OPTION_CONFLICT_SHORT "%c should not be used together with %c\n" 24 | 25 | #define CLA_MSG_NO_FILENAME "No filename\n" 26 | #define CLA_MSG_IO_ERROR "%s: %s\n" 27 | #define CLA_MSG_SELF_RECURSION "File %s, line %d, including himself (ignoring)\n" 28 | #define CLA_MSG_FILE_UNKNOWN_OPTION "File %s, line %d: %s - unrecognized\n" 29 | #define CLA_MSG_FILE_NO_ENOUGH_ARGS "File %s, line %d: %s - no enough arguments\n" 30 | #define CLA_MSG_FILE_TOO_MUCH_ARGS "File %s, line %d: %s - too many arguments\n" 31 | #define CLA_MSG_FILE_OPTION_REQUED "File %s, line %d: %s - requed argument missed\n" 32 | #define CLA_MSG_FILE_INCORRECT_ARG "File %s, line %d: %s - incorrect type of argument\n" 33 | #define CLA_MSG_FILE_CONFLICT "File %s, line %d: %s - conflict with %s (should not be used together)\n" 34 | 35 | #define CLA_MSG_ENV_NO_ENOUGH_ARGS "Environment line %s has no enough arguments\n" 36 | #define CLA_MSG_ENV_TOO_MUCH_ARGS "Environment line %s has too much arguments\n" 37 | #define CLA_MSG_ENV_OPTION_REQUED "Environment line %s should has argument\n" 38 | #define CLA_MSG_ENV_INCORRECT_ARG "Environment line %s has wrong argument type\n" 39 | #define CLA_MSG_ENV_CONFLICT "Environment line %s should not be used together with %s\n" 40 | 41 | 42 | #define CLA_MSG_INCORRECT_CALL "Incorrect library call (internal application error)\n" 43 | 44 | #define CLA_MSG_NONSAVABLE "Option '%s' not saved\n" 45 | 46 | #define CLA_MSG_TEXT_CONFIG_HEAD "# configuration file\n# character '#' at line begin comment line\n# sytax:\n# name = value\n# name = value1;value2;...;valueNN\n\n" 47 | 48 | 49 | #define CLA_MSG_ENV_NOT_ENOUGH "Environment line %s has no enough arguments\n" 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/colian/init-close.c: -------------------------------------------------------------------------------- 1 | #include "colian.h" 2 | #include "internal.h" 3 | 4 | claCfg_t* claInit( int OptListNum, int maxFreeOpt ){ 5 | 6 | claCfg_t* retval = calloc( 1, sizeof(claCfg_t) ); 7 | retval->item = calloc( sizeof(claCfgItem_t), OptListNum ); 8 | retval->entryNum = OptListNum; 9 | retval->FreeOpt = calloc( sizeof(char*), maxFreeOpt ); 10 | 11 | return retval; 12 | 13 | } 14 | 15 | void claClose( claCfg_t* c ){ 16 | 17 | int i, j; 18 | 19 | if( !c ) 20 | return; 21 | 22 | for( i=0; ientryNum; i++ ){ 23 | if( c->item[i].found) { 24 | if( c->item[i].type & CLA_TYPE_STRING ){ 25 | for( j=0; jitem[i].argNum; j++ ) 26 | free( c->item[i].slist[j] ); 27 | free( c->item[i].slist ); 28 | } 29 | else 30 | if(c->item[i].argNum) 31 | free( c->item[i].nlist ); 32 | } 33 | } 34 | 35 | for( i=0; i< c->FreeOptNum; i++ ) 36 | free ( c->FreeOpt[i] ); 37 | 38 | if( c->FreeOpt ) 39 | free( c->FreeOpt ); 40 | 41 | free( c->item ); 42 | 43 | free( c ); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/colian/internal.h: -------------------------------------------------------------------------------- 1 | claCfg_t* claInit( int OptListNum, int maxFreeOpt ); 2 | int ClassOpt( char* line ); 3 | int OptNameCmp( const char* sample, const char* name, int case_ignore_flag ); 4 | int GetOptionID( 5 | const char* line, 6 | const claOptName_t* OptList, 7 | const int OptListNum, 8 | int type 9 | ); 10 | 11 | int GetShortOptOdd( const char letter, claOptName_t* OptList, const int OptListNum ); 12 | 13 | int SetArguments(const char* line, claOptName_t* optN, claCfgItem_t* optV ); 14 | 15 | int GetLine( FILE* from, char** target, int *target_size ); 16 | 17 | void CropComment( char* line ); 18 | 19 | char* SkipSpaces(const char* line); 20 | 21 | char* SkipEquiv(const char* line); 22 | 23 | void CropCommentAndCRLF(char* line); 24 | 25 | int LineToOpt(claCfg_t* cfg,claOptName_t* opt, int optn, char* parse_line, int area ); 26 | -------------------------------------------------------------------------------- /src/colian/join.c: -------------------------------------------------------------------------------- 1 | #include "colian.h" 2 | #include "internal.h" 3 | 4 | claCfg_t* claJoin(claCfg_t* config1, claCfg_t* config2, int Priority1, int Priority2){ 5 | 6 | claCfg_t* source; 7 | claCfg_t* target; 8 | 9 | int c; 10 | 11 | if( !config1 && config2 ) 12 | return config2; 13 | 14 | if( config2 && !config1 ) 15 | return config1; 16 | 17 | if(!config1 && config2 ) 18 | return NULL; 19 | 20 | if( config1->entryNum != config2->entryNum ) 21 | return NULL; 22 | 23 | if( Priority2 >= Priority1 ){ 24 | source = config1; 25 | target = config2; 26 | }else{ 27 | source = config2; 28 | target = config1; 29 | } 30 | 31 | for( c=0; c < source->entryNum; c++ ){ 32 | if( source->item[c].found && !target->item[c].found ){ 33 | if( claGroupOpt( target, source->item[c].type & CLA_GROUP_ALL ) < 0 ){ 34 | target->item[c] = source->item[c]; 35 | source->item[c].found = 0; /*disable record to awoid double free for strings*/ 36 | }else{ 37 | /*todo: error handling*/ 38 | } 39 | } 40 | } 41 | 42 | if( source->FreeOptNum ){ 43 | 44 | target->FreeOpt = realloc( 45 | target->FreeOpt, 46 | sizeof( char* ) * ( target->FreeOptNum + source->FreeOptNum ) 47 | ); 48 | assert( target ); 49 | 50 | for( c=0; c < source->FreeOptNum; c++ ){ 51 | target->FreeOpt[target->FreeOptNum + c] = source->FreeOpt[c]; 52 | } 53 | 54 | target->FreeOptNum += source->FreeOptNum; 55 | source->FreeOptNum = 0; /*to avoid double free to FreeOpt in claClose()*/ 56 | 57 | } 58 | 59 | claClose( source ); 60 | 61 | return target; 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/colian/print.c: -------------------------------------------------------------------------------- 1 | #include "colian.h" 2 | #include "internal.h" 3 | 4 | void claPrintOpt( claOptName_t* OptList, int OptListN, FILE* to ){ 5 | 6 | int c; 7 | int lopt_size = 1; 8 | int tmp; 9 | char lopt_print_tpl [128]; 10 | 11 | if( OptList && OptListN ){ 12 | 13 | for( c=0; c < OptListN; c++ ){ 14 | if( OptList[c].optName[0] && (OptList[c].optType & CLA_CMD ) ){ 15 | tmp = strlen( OptList[c].optName ); 16 | if( tmp > lopt_size ) lopt_size = tmp; 17 | } 18 | } 19 | 20 | if( lopt_size > 50 ) 21 | lopt_size = 50; /*TODO error message here?*/ 22 | 23 | sprintf( lopt_print_tpl, "--%%-%ds", lopt_size + 1 ); 24 | 25 | for( c=0; c < OptListN; c++ ){ 26 | 27 | if( ! ( OptList[c].optType & CLA_CMD ) ) 28 | continue; 29 | 30 | if( OptList[c].optLetter ) 31 | fprintf( to, "-%c, ", OptList[c].optLetter ); 32 | else 33 | fprintf( to, " " ); 34 | if( OptList[c].optName[0] ) 35 | fprintf( to, lopt_print_tpl, OptList[c].optName ); 36 | else 37 | fprintf( to, " " ); 38 | if( OptList[c].description ) 39 | fprintf( to, "%s", OptList[c].description ); 40 | fprintf( to, "\n" ); 41 | 42 | } 43 | } 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/colian/read.c: -------------------------------------------------------------------------------- 1 | #include "colian.h" 2 | #include "internal.h" 3 | #define DEFAULT_LINE_BUFFER_SIZE 128 4 | 5 | /** 6 | * read line from text file 7 | * behavior is not defined if file contains a zero (0x00) character 8 | * return number of readed characterss or zero, if no characters has been 9 | * readed (EOF or i/o error) 10 | * put readed string to *target, size is keeping in *target_size. 11 | * if ** target is a NULL, *target contain a dynamically allocated string 12 | * (independ on success of reading). 13 | * return string allways ending by 0-character. 14 | 15 | **/ 16 | 17 | 18 | int GetLine( FILE* from, char** target, int *target_size ){ 19 | 20 | #if DEFAULT_LINE_BUFFER_SIZE < 2 21 | #error DEFAULT_LINE_BUFFER_SIZE must be >= 2 22 | #endif 23 | 24 | int block_size = DEFAULT_LINE_BUFFER_SIZE; 25 | int offset = 0; 26 | 27 | if( !*target ){ 28 | *target = malloc( DEFAULT_LINE_BUFFER_SIZE ); 29 | assert( *target ); 30 | (*target)[0] = 0; 31 | *target_size = DEFAULT_LINE_BUFFER_SIZE; 32 | } 33 | 34 | while( fgets( *target + offset, block_size, from ) ){ 35 | offset += strlen( *target + offset ); 36 | 37 | if( offset < 2 ) 38 | break; 39 | 40 | if( (*target)[offset - 1] == '\n' || (*target)[offset - 1] == '\r' ) 41 | break; 42 | 43 | block_size += block_size/2; 44 | *target_size += block_size; 45 | *target = realloc( *target, *target_size ); 46 | assert( *target ); 47 | } 48 | 49 | return offset; 50 | } 51 | 52 | void CropComment( char* line ){ 53 | char* p=line; 54 | while(*p) 55 | if(*p=='#'){ 56 | *p=0; 57 | break; 58 | } 59 | } 60 | 61 | 62 | void CropCommentAndCRLF(char* line){ 63 | int i; 64 | for(i=0;line[i];i++){ 65 | if(line[i]=='\n'||line[i]=='\t'||line[i]=='#'){ 66 | line[i]=0; 67 | return; 68 | } 69 | } 70 | } 71 | 72 | 73 | 74 | 75 | int CheckInclude( const char* line){ 76 | /*check for 'include' word and return offset to start of word after include. Return 0 if no 'include' found*/ 77 | unsigned int include_len = strlen( CLA_KEYWORD_INCLUDE ); 78 | char* p = SkipSpaces( line ); 79 | 80 | if( p ){ 81 | if( strlen( p ) > include_len ){ 82 | if(!memcmp(CLA_KEYWORD_INCLUDE,p,include_len)){ 83 | if(p[include_len]==' '||p[include_len]=='\t') 84 | return (int)(SkipSpaces(p+include_len)-line); 85 | } 86 | } 87 | } 88 | return 0; 89 | } 90 | 91 | 92 | claCfg_t* claReadTextConfig( const char* FileName, claOptName_t* OptList, int OptListNum, int Ctrl ){ 93 | 94 | claCfg_t* retval; 95 | FILE* handle; 96 | char* buf = NULL; 97 | int buf_size = 0; 98 | char* line; 99 | int line_counter = 0; 100 | int include_position= 0; 101 | int silence_flag = Ctrl & CLA_FLAG_SILENCE; 102 | int result_code = 0; 103 | 104 | struct { 105 | int flag; 106 | char* msg; 107 | }read_error_act[]={ 108 | { 0, NULL }, /*skip*/ 109 | { 0, NULL }, /*skip*/ 110 | { CLA_FLAG_STOP_UNKNOWN, CLA_MSG_FILE_UNKNOWN_OPTION }, /*unknown option*/ 111 | { CLA_FLAG_STOP_NOT_ENOUGH, CLA_MSG_FILE_NO_ENOUGH_ARGS }, /*not enough arguments*/ 112 | { CLA_FLAG_STOP_TOO_MUCH, CLA_MSG_FILE_TOO_MUCH_ARGS }, /*too many arguments*/ 113 | { CLA_FLAG_STOP_OPTION_REQUED, CLA_MSG_FILE_OPTION_REQUED }, /*no eny arguments found*/ 114 | { CLA_FLAG_STOP_INCORRECT_ARG, CLA_MSG_FILE_INCORRECT_ARG }, /*incorrect argument type*/ 115 | }; 116 | 117 | 118 | if( !FileName ){ 119 | if( !silence_flag ) 120 | printf( CLA_MSG_NO_FILENAME ); 121 | return NULL; 122 | } 123 | 124 | handle = fopen( FileName, "r" ); 125 | if( !handle ){ 126 | if(!silence_flag) 127 | printf( CLA_MSG_IO_ERROR, FileName, strerror(errno) ); 128 | return NULL; 129 | } 130 | 131 | retval = claInit( OptListNum, 0 ); 132 | 133 | assert( retval ); 134 | 135 | while( GetLine( handle, &buf, &buf_size ) ){ 136 | 137 | line_counter++; 138 | 139 | CropCommentAndCRLF( buf ); 140 | 141 | line = SkipSpaces( buf ); 142 | if( !*line ) 143 | continue; 144 | 145 | if( (Ctrl&CLA_FLAG_ENABLE_INCLUDE) ){ 146 | include_position = CheckInclude( line ); 147 | if( include_position ){ 148 | if( !strcmp( FileName, line + include_position ) ){ 149 | if(!silence_flag) 150 | printf(CLA_MSG_SELF_RECURSION, FileName,line_counter); 151 | continue; 152 | } 153 | retval = claJoin( /*joining current config and included (priority to included) */ 154 | retval, 155 | claReadTextConfig( line + include_position, OptList, OptListNum, Ctrl ), 156 | 0,1 157 | ); 158 | continue; 159 | } 160 | } 161 | 162 | result_code = LineToOpt( retval, OptList, OptListNum, line, CLA_CFG ); 163 | 164 | if( result_code >= 0 ){/*error handling, conflict option*/ 165 | if(! silence_flag) 166 | printf(CLA_MSG_FILE_CONFLICT, FileName, line_counter, line, OptList[result_code].optName ); 167 | if( Ctrl & CLA_FLAG_STOP_CONFLICT ){ 168 | claClose( retval ); 169 | fclose( handle ); 170 | free( buf ); 171 | return NULL; 172 | } 173 | continue; 174 | } 175 | 176 | if( result_code < -1 ){/*error handling, notfound/arguments, etc*/ 177 | assert( result_code >= -6 ); 178 | if(!silence_flag) 179 | printf( read_error_act[ 0 - result_code ].msg, FileName, line_counter, line ); 180 | if(Ctrl & read_error_act[ 0 - result_code ].flag ){ 181 | fclose( handle ); 182 | claClose( retval ); 183 | free( buf ); 184 | return NULL; 185 | } 186 | continue; 187 | } 188 | } 189 | fclose(handle); 190 | free( buf ); 191 | return retval; 192 | 193 | } 194 | -------------------------------------------------------------------------------- /src/colian/write.c: -------------------------------------------------------------------------------- 1 | #include "colian.h" 2 | #include "internal.h" 3 | 4 | 5 | int claWriteTextConfig(claCfg_t* cfg, const char* FileName, claOptName_t* OptList, int OptListNum, int Ctrl ){ 6 | 7 | FILE* handle; 8 | int c; 9 | int i; 10 | int flag_saved_item=0; 11 | 12 | if( cfg->entryNum != OptListNum ) { 13 | if( !( Ctrl & CLA_FLAG_SILENCE ) ){ 14 | printf( CLA_MSG_INCORRECT_CALL ); 15 | } 16 | return -1; 17 | } 18 | 19 | if( !FileName ){ 20 | if( !( Ctrl & CLA_FLAG_SILENCE ) ) 21 | printf( CLA_MSG_NO_FILENAME ); 22 | return -1; 23 | } 24 | 25 | handle = fopen( FileName, "w" ); 26 | if( !handle ){ 27 | if( !( Ctrl & CLA_FLAG_SILENCE ) ) 28 | printf( CLA_MSG_IO_ERROR, FileName, strerror( errno ) ); 29 | return -1; 30 | } 31 | 32 | if( Ctrl & CLA_FLAG_HEAD_INFO ) 33 | fprintf( handle, CLA_MSG_TEXT_CONFIG_HEAD ); 34 | 35 | for( c = 0; c < cfg->entryNum; c++ ){ 36 | 37 | flag_saved_item = 0; 38 | 39 | if( cfg->item[c].found || ( Ctrl & CLA_FLAG_SAVE_ALL ) ){ 40 | 41 | if( !( Ctrl & CLA_FLAG_IGNORE_NONSAVABLE ) ){ 42 | 43 | if( !( OptList[c].optType & CLA_CFG ) ){ 44 | 45 | if( !( Ctrl&CLA_FLAG_SILENCE ) ) 46 | printf( CLA_MSG_NONSAVABLE, OptList[c].optName ); 47 | 48 | if( !( Ctrl & CLA_FLAG_STOP_NONSAVABLE ) ){ 49 | fclose( handle ); 50 | /*add delete*/ 51 | return 0; 52 | } 53 | 54 | continue; 55 | } 56 | } 57 | 58 | if( ( OptList[c].optType & CLA_CFG ) || (Ctrl & CLA_FLAG_SAVE_ALL) ){ 59 | 60 | flag_saved_item = 1; 61 | 62 | fprintf( handle, "%s = ", OptList[c].optName ); /*add error checking*/ 63 | 64 | for( i=0; i < cfg->item[c].argNum; i++ ){ 65 | 66 | if( cfg->item[c].type & CLA_TYPE_STRING ) 67 | fprintf( handle, "%s", cfg->item[c].slist[i] ); 68 | else 69 | fprintf( handle, "%d", cfg->item[c].nlist[i]); 70 | 71 | if( i + 1 < cfg->item[c].argNum ) 72 | fprintf( handle, ";" ); 73 | 74 | } 75 | fprintf( handle, "\n" ); 76 | } 77 | 78 | }else{ 79 | 80 | if( ( (Ctrl & CLA_FLAG_SAVE_NOTFOUND) && ( OptList[c].optType & CLA_CFG ) ) || ( Ctrl & CLA_FLAG_SAVE_ALL ) ){ 81 | 82 | flag_saved_item = 1; 83 | 84 | fprintf( handle, "#%s=", OptList[c].optName ); 85 | 86 | if( OptList[c].optType & CLA_TYPE_STRING ) 87 | fprintf( handle, " \n" ); 88 | else 89 | fprintf( handle, "0\n" ); 90 | 91 | } 92 | 93 | } 94 | 95 | if( flag_saved_item && ( Ctrl & CLA_FLAG_OPT_COMMENT ) ){ 96 | fprintf( handle, "# %s: %s\n\n", OptList[c].optName, OptList[c].description ); 97 | } 98 | 99 | } 100 | 101 | fclose( handle ); 102 | 103 | return 1; 104 | 105 | } 106 | 107 | -------------------------------------------------------------------------------- /src/common.c: -------------------------------------------------------------------------------- 1 | /* non-io functions */ 2 | #include 3 | #include 4 | #include 5 | 6 | long long compare_mem(unsigned char *one, unsigned char *two, long long size){ 7 | long long diff_counter=0; 8 | long long counter=0; 9 | while(counter>1; 26 | c++; 27 | } 28 | up=up<size-up) 31 | return up; 32 | else 33 | return down; 34 | } 35 | 36 | long long delta(long long size){ 37 | long long pow; 38 | pow=get_near_round_value(size); 39 | if(pow>size) 40 | return pow-size; 41 | else 42 | return size-pow; 43 | } 44 | 45 | char* human_view( const long long size, const char postletter ){ 46 | long long divider; 47 | char postfix; 48 | static char ret_buffer[255]; 49 | 50 | if(size<0){ 51 | return " -not avaible- "; 52 | } 53 | 54 | if(size>10*(long long)1024*(long long)1024*(long long)1024){ 55 | postfix='G'; 56 | divider=1024*1024*1024; 57 | }else{ 58 | if( size>10485760 ){ 59 | postfix='M'; 60 | divider=1024*1024; 61 | }else{ 62 | if( size>10240 ){ 63 | postfix='k'; 64 | divider=1024; 65 | } 66 | else{ 67 | postfix=postletter; 68 | divider=1; 69 | } 70 | } 71 | } 72 | 73 | snprintf(ret_buffer,255,"%I64i %c%c",size/divider,postfix, postfix==postletter?0:postletter); 74 | return ret_buffer; 75 | } 76 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_COMMON_H 2 | #define _H_COMMON_H 3 | 4 | long long compare_mem(unsigned char *one, unsigned char *two, long long size); 5 | long long get_near_round_value(long long size); 6 | long long delta(long long size); 7 | char* human_view( const long long size, const char postletter ); 8 | void bitfield(char* buff,int value); 9 | 10 | /* Somehow safe for overflow vesion of MULDIV(A,B,C) =A*B/C */ 11 | 12 | 13 | //#define MULDIV(A,B,C) ((A*B>A)?((A*B)/C):((max(A,B)/C)*min(A,B))) 14 | /*Interger (not very good)*/ 15 | 16 | #define MULDIV(A,B,C) ((long long)( (double)A* (double)B / (double)C )) 17 | /*float point version*/ 18 | 19 | 20 | 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/ddk.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_DDK_H 2 | #define _H_DDK_H 3 | /*requed defenition from DDK. 4 | thanks to Stanislav Golovnin for adaptation microsoft sample of code to GCC.*/ 5 | 6 | //#pragma pack (push,4) 7 | typedef enum _STORAGE_QUERY_TYPE { 8 | PropertyStandardQuery = 0, // Retrieves the descriptor 9 | PropertyExistsQuery, // Used to test whether the descriptor is supported 10 | PropertyMaskQuery, // Used to retrieve a mask of writeable fields in the descriptor 11 | PropertyQueryMaxDefined // use to validate the value 12 | } STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE; 13 | 14 | // 15 | // define some initial property id's 16 | typedef enum _STORAGE_PROPERTY_ID { 17 | StorageDeviceProperty = 0, 18 | StorageAdapterProperty, 19 | StorageDeviceIdProperty 20 | } STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID; 21 | 22 | // 23 | // Query structure - additional parameters for specific queries can follow 24 | // the header 25 | typedef struct _STORAGE_PROPERTY_QUERY { 26 | STORAGE_PROPERTY_ID PropertyId; // ID of the property being retrieved 27 | STORAGE_QUERY_TYPE QueryType; // Flags indicating the type of query being performed 28 | UCHAR AdditionalParameters[1]; // Space for additional parameters if necessary 29 | 30 | } STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY; 31 | 32 | 33 | typedef struct _STORAGE_ADAPTER_DESCRIPTOR { 34 | ULONG Version; 35 | ULONG Size; 36 | ULONG MaximumTransferLength; 37 | ULONG MaximumPhysicalPages; 38 | ULONG AlignmentMask; 39 | BOOLEAN AdapterUsesPio; 40 | BOOLEAN AdapterScansDown; 41 | BOOLEAN CommandQueueing; 42 | BOOLEAN AcceleratedTransfer; 43 | UCHAR BusType; 44 | USHORT BusMajorVersion; 45 | USHORT BusMinorVersion; 46 | } STORAGE_ADAPTER_DESCRIPTOR, *PSTORAGE_ADAPTER_DESCRIPTOR; 47 | 48 | #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m)) 49 | 50 | DEFINE_GUID( GUID_DEVCLASS_DISKDRIVE, 0x4d36e967L, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 ); 51 | DEFINE_GUID(GUID_DEVINTERFACE_DISK, 0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); 52 | 53 | #ifndef STORAGE_BUS_TYPE // MINGW 54 | typedef enum _STORAGE_BUS_TYPE { 55 | BusTypeUnknown = 0x00, 56 | BusTypeScsi, 57 | BusTypeAtapi, 58 | BusTypeAta, 59 | BusType1394, 60 | BusTypeSsa, 61 | BusTypeFibre, 62 | BusTypeUsb, 63 | BusTypeRAID, 64 | BusTypeiScsi, 65 | BusTypeSas, 66 | BusTypeSata, 67 | BusTypeMaxReserved = 0x7F 68 | } STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE; 69 | #endif 70 | 71 | typedef struct _STORAGE_DEVICE_DESCRIPTOR { 72 | ULONG Version; // Sizeof(STORAGE_DEVICE_DESCRIPTOR) 73 | 74 | // Total size of the descriptor, including the space for additional 75 | // data and id strings 76 | ULONG Size; 77 | UCHAR DeviceType; // The SCSI-2 device type 78 | UCHAR DeviceTypeModifier; // The SCSI-2 device type modifier (if any) - this may be zero 79 | 80 | // Flag indicating whether the device's media (if any) is removable. This 81 | // field should be ignored for media-less devices 82 | BOOLEAN RemovableMedia; 83 | 84 | // Flag indicating whether the device can support mulitple outstanding 85 | // commands. The actual synchronization in this case is the responsibility 86 | // of the port driver. 87 | BOOLEAN CommandQueueing; 88 | 89 | // Byte offset to the zero-terminated ascii string containing the device's 90 | // vendor id string. For devices with no such ID this will be zero 91 | ULONG VendorIdOffset; 92 | 93 | // Byte offset to the zero-terminated ascii string containing the device's 94 | // product id string. For devices with no such ID this will be zero 95 | ULONG ProductIdOffset; 96 | 97 | // Byte offset to the zero-terminated ascii string containing the device's 98 | // product revision string. For devices with no such string this will be 99 | // zero 100 | ULONG ProductRevisionOffset; 101 | 102 | // Byte offset to the zero-terminated ascii string containing the device's 103 | // serial number. For devices with no serial number this will be zero 104 | ULONG SerialNumberOffset; 105 | 106 | // Contains the bus type (as defined above) of the device. It should be 107 | // used to interpret the raw device properties at the end of this structure 108 | // (if any) 109 | STORAGE_BUS_TYPE BusType; 110 | ULONG RawPropertiesLength; // The number of bytes of bus-specific data which have been appended to this descriptor 111 | UCHAR RawDeviceProperties[1]; // Place holder for the first byte of the bus specific property data 112 | 113 | } STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR; 114 | 115 | typedef struct _STORAGE_HOTPLUG_INFO { 116 | 117 | UINT Size; 118 | UCHAR MediaRemovable; 119 | UCHAR MediaHotplug; 120 | UCHAR DeviceHotplug; 121 | UCHAR WriteCacheEnableOverride; 122 | } STORAGE_HOTPLUG_INFO, 123 | 124 | *PSTORAGE_HOTPLUG_INFO; 125 | 126 | 127 | //#define FILE_DEVICE_MASS_STORAGE 0x0000002d 128 | #define IOCTL_STORAGE_QUERY_PROPERTY CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) 129 | #define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE 130 | #define IOCTL_STORAGE_GET_HOTPLUG_INFO ( (IOCTL_STORAGE_BASE << 16) | (FILE_ANY_ACCESS << 14) | (0x0305 << 2) | METHOD_BUFFERED ) 131 | #define FSCTL_ALLOW_EXTENDED_DASD_IO CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 32, METHOD_NEITHER, FILE_ANY_ACCESS) 132 | //#define FILE_ANY_ACCESS 0 133 | #define METHOD_BUFFERED 0 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /src/detect.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "detect.h" 6 | #include "common.h" 7 | 8 | DWORD get_drive_type(char* path){ 9 | char buffer[MAX_PATH]; 10 | strncpy(buffer,path,MAX_PATH); 11 | strncat(buffer,"\\",MAX_PATH); 12 | return GetDriveType(buffer); 13 | } 14 | 15 | 16 | 17 | const char* get_drive_type_string(char* path){ 18 | 19 | int c; 20 | struct drive_string_list_s{ 21 | DWORD ID; 22 | const char* string; 23 | }strings[]={ 24 | { DRIVE_UNKNOWN, "Unknown" }, 25 | { DRIVE_NO_ROOT_DIR, "No root dir (not mounted device)" }, 26 | { DRIVE_REMOVABLE, "Removable" }, 27 | { DRIVE_FIXED, "Fixed" }, 28 | { DRIVE_REMOTE, "Network or remote device" }, 29 | { DRIVE_CDROM, "CD/DVD" }, 30 | { DRIVE_RAMDISK, "RAM-drive" } 31 | }; 32 | DWORD type=get_drive_type( path ); 33 | for(c=0;c65535 ){ 52 | printf("GetLogicalDriveStrings() fails\n"); 53 | return; 54 | } 55 | 56 | 57 | buff=malloc(req_space+1); 58 | assert(buff); 59 | curr=buff; 60 | res_space = GetLogicalDriveStrings( req_space, buff ); 61 | printf("\nAvaible logical disks:\n"); 62 | while( *curr ){ 63 | curr_len = strlen( curr ); 64 | printf( "%s\t", curr ); 65 | if( !flags & 0x0100 ) 66 | printf("type=%u (%s)", 67 | (unsigned int)get_drive_type(curr), 68 | get_drive_type_string(curr) 69 | ); 70 | printf("\n"); 71 | curr+=curr_len+1; 72 | } 73 | } 74 | 75 | 76 | void list_physical_drives(){ 77 | char d1; 78 | char d2; 79 | dev_ctrl_t* dev; 80 | char pattern[]="PhysicalDrive$$"; 81 | assert(pattern[13]=='$'&&pattern[14]=='$'); 82 | printf("\nAvaible physical drives:\n"); 83 | 84 | for(d1='0';d1<='9';d1++){ 85 | for(d2='0';d2<='9';d2++){ 86 | if(d1=='0'){ 87 | pattern[13]=d2; 88 | pattern[14]=0; 89 | }else{ 90 | pattern[13]=d1; 91 | pattern[14]=d2; 92 | } 93 | dev = open_drive( pattern, 1, 0 ); 94 | if(dev){ 95 | printf("%d\tsize = %I64d (%s)\n", 96 | (d1-'0')*10+d2-'0', 97 | get_device_size(dev), 98 | human_view(get_device_size(dev), 'b') 99 | ); 100 | close_drive(dev); 101 | } 102 | } 103 | 104 | } 105 | 106 | } 107 | 108 | 109 | 110 | void list_disks(int flags){ 111 | 112 | int display = flags?flags:0xFF; 113 | 114 | if(display&0x1) 115 | list_physical_drives(); 116 | if(display&0x2) 117 | list_logical_drives(display&0xFF00); 118 | } 119 | -------------------------------------------------------------------------------- /src/detect.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_DETECT_H 2 | #define _H_DETECT_H 3 | #include "io.h" 4 | void list_disks(int flaglist); 5 | #endif 6 | 7 | -------------------------------------------------------------------------------- /src/display.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "display.h" 6 | #include "common.h" 7 | #include "finetune.h" 8 | 9 | void wait_for_key(char* text){ 10 | fprintf(stderr,text); 11 | getchar(); 12 | } 13 | 14 | 15 | void bitfield(char* buff,int value){ 16 | int c; 17 | assert(value<256&&value>=0); 18 | for(c=7;c>=0;c--){ 19 | if(value & (1<=max_diff) 37 | return; 38 | diff_counter++; 39 | bitfield(one_buff,one[counter]); 40 | bitfield(two_buff,two[counter]); 41 | bitfield(diff_buff,one[counter]^two[counter]); 42 | printf("0x%010I64x:\t%s (0x%02X) | %s (0x%02X) | %s\n", offset + counter, one_buff,one[counter],two_buff,two[counter],diff_buff); 43 | } 44 | counter++; 45 | 46 | } 47 | 48 | } 49 | 50 | 51 | 52 | void display_drive_info(dev_ctrl_t* dev){ 53 | printf( "\n\nDisk %s (UNC name: %s)\n", dev->user_name, dev->system_name ); 54 | 55 | if( dev->drive_geometry_flag ){ 56 | 57 | print_header( "[Drive geometry]"); 58 | printf( "Cylinders/heads/sectors\t = %I64d/%I64d/%I64d\n", dev->cylinders,dev->tracks_per_cylinder,dev->sectors_per_track ); 59 | printf( "Bytes per sector\t = %I64d\n", dev->sector_size ); 60 | printf( "CHS size\t\t = %I64d (%s)\n", dev->geometry_size, human_view( dev->geometry_size, 'b' ) ); 61 | 62 | } 63 | 64 | if( dev->disk_space_flag ){ 65 | 66 | print_header( "[Free Space]"); 67 | printf( "Total space\t\t = %I64d\n", dev->disk_size ); 68 | printf( "Free space\t\t = %I64d\n", dev->free_size ); 69 | if( dev->free_size != dev->avaible_size ) 70 | printf( "Avaible space\t\t = %I64d (diff: %I64d)\n", dev->avaible_size, dev->avaible_size - dev->free_size ); 71 | 72 | } 73 | 74 | if( dev->drive_length_flag ){ 75 | print_header("[Device size]" ); 76 | printf("Device size\t\t = %I64d (%s)\n",dev->device_size,human_view(dev->device_size, 'b')); 77 | printf("delta to near power of 2 = %I64d (%s), %I64d%%\n", delta(dev->device_size), human_view(delta(dev->device_size),'b'),(100*delta(dev->device_size))/dev->device_size); 78 | if( dev->physical_flag )printf("Surplus size\t\t = %I64d (%s)\n",dev->device_size-dev->geometry_size,human_view(dev->device_size-dev->geometry_size, 'b')); 79 | 80 | } 81 | if( dev->adapter_flag || dev->device_flag ) 82 | print_header( "[Adapter & Device properties]" ); 83 | 84 | if( dev->adapter_flag ) 85 | printf( "Bus type\t\t = (%d) %s\n",dev->bus_type, dev->bus_name ); 86 | 87 | if( dev->device_flag ){ 88 | 89 | printf( "Removable device\t = %s\n", dev->removable ? "Yes" : "No" ); 90 | printf( "Command Queue\t\t = %s\n", dev->CQ ? "Supported" : "Unsupported" ); 91 | if( dev->vendor[0] ) 92 | printf( "Device vendor\t\t = %s\n", dev->vendor ); 93 | if( dev->name[0] ) 94 | printf( "Device name\t\t = %s\n", dev->name ); 95 | if( dev->revision[0] ) 96 | printf( "Revision\t\t = %s\n", dev->revision ); 97 | if( dev->serial[0] ) 98 | printf( "Device serial\t\t = %s\n", dev->serial ); 99 | // if( dev->raw_serial[0] ) 100 | // printf( "Device raw serial= %s\n",dev->raw_serial ); 101 | 102 | } 103 | 104 | if (dev->hotplug_info_flag ){ 105 | print_header( "[Hotplug info]" ); 106 | printf( "Device hotplug\t\t = %s\n", dev->device_hotplug ? "Yes" : "No" ); 107 | printf( "Media hotplug\t\t = %s\n", dev->media_hotplug ? "Yes" : "No" ); 108 | } 109 | 110 | } 111 | 112 | 113 | void print_header( char* text ){ 114 | 115 | char buffer[LINE_LENGTH+1]; 116 | int len = strlen(text); 117 | 118 | assert( len < LINE_LENGTH - 2 ); 119 | 120 | memset( buffer, '-', LINE_LENGTH - len - 2 ); 121 | memcpy( buffer + LINE_LENGTH - 2 - len, text, len ); 122 | memcpy( buffer + LINE_LENGTH - 2, "--", 3 ); 123 | puts( buffer ); 124 | 125 | } 126 | 127 | 128 | void print_footer(dev_ctrl_t* dev){ 129 | printf("\n"); 130 | print_header( "[Operation result]" ); 131 | printf( "passes:\t\t\t%I64d\n", dev->pass_count ); 132 | printf( "errors:\t\t\t%I64d\n", dev->error_count ); 133 | if(!dev->size) 134 | printf("warining:\t\tdevice size unknown, all test skipped\n"); 135 | if( dev->read_bytes ) 136 | printf( "read bytes:\t\t%I64d (%s)\n", dev->read_bytes, human_view( dev->read_bytes, 'b' ) ); 137 | if(dev->read_counts){ 138 | printf( "avg. read speed:\t%I64d (%s/s)\n", 139 | MULDIV (dev->read_bytes, dev->freq, dev->read_counts ), 140 | human_view( MULDIV( dev->read_bytes, dev->freq, dev->read_counts ), 'b' ) 141 | ); 142 | printf("max/min read speed:\t%I64d (%s/s) / ", dev->max_read_speed, human_view( dev->max_read_speed, 'b' ) ); 143 | printf("%I64d (%s/s)\n", dev->min_read_speed, human_view( dev->min_read_speed, 'b' ) ); 144 | } 145 | if( dev->write_bytes ) 146 | printf( "write bytes:\t\t%I64d (%s)\n", dev->write_bytes, human_view( dev->write_bytes, 'b' ) ); 147 | if( dev->write_counts ){ 148 | printf( "avg. write speed:\t%I64d (%s/s)\n", 149 | MULDIV( dev->write_bytes, dev->freq, dev->write_counts ), 150 | human_view( MULDIV (dev->write_bytes, dev->freq, dev->write_counts), 'b' ) 151 | ); 152 | printf("max/min write speed:\t%I64d (%s/s) / ", dev->max_write_speed, human_view( dev->max_write_speed, 'b' ) ); 153 | printf("%I64d (%s/s)\n", dev->min_write_speed, human_view( dev->min_write_speed, 'b' ) ); 154 | } 155 | } 156 | 157 | void clearline(){ 158 | char* spaceline=_alloca(LINE_LENGTH+2); 159 | memset(spaceline+1,' ',LINE_LENGTH); 160 | spaceline[0]='\r'; 161 | spaceline[LINE_LENGTH]=0; 162 | fprintf(stderr,spaceline); 163 | } 164 | -------------------------------------------------------------------------------- /src/display.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_DISPLAY_H 2 | #define _H_DISPLAY_H 3 | #include 4 | #include 5 | #include "io.h" 6 | #include "flashnul.h" 7 | char* human_view( const long long size, const char postletter ); 8 | long long delta(long long size); 9 | void print_bit_dump( unsigned char* one, unsigned char* two, long long size, long long offset, int max_diff); 10 | void wait_for_key(char* text); 11 | char* human_view( const long long size, const char postletter ); 12 | void display_drive_info(dev_ctrl_t* dev); 13 | void clearline(); 14 | enum{ 15 | MSG_LOGABLE, 16 | MSG_DISPLAY_ONLY, 17 | MSG_CRASH 18 | }; 19 | void print_header( char* text ); 20 | void print_footer(dev_ctrl_t* dev); 21 | #endif 22 | -------------------------------------------------------------------------------- /src/finetune.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_FINETUNE_H 2 | #define _H_FINETUNE_H 3 | 4 | #define REFRESH_DELAY 100 5 | /*delay between outputs in ms*/ 6 | 7 | #define LINE_LENGTH 78 8 | /*default output line length*/ 9 | 10 | 11 | #define HOME_DIR_CONFIG 1 12 | /* is a config name a name of file in home directory of program?*/ 13 | 14 | #define CONFIG_FILE "flashnul.conf" 15 | /* name of configuration file*/ 16 | 17 | #define ADVANCED_RECOVERY_BEEP 0 18 | /*beep in advanced recovery at errors*/ 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/flashnul.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "io.h" 3 | #include "generate.h" 4 | #include "display.h" 5 | #include "colian/colian.h" 6 | #include "flashnul.h" 7 | #include "actions.h" 8 | #include "detect.h" 9 | #include "finetune.h" 10 | #include "advanced.h" 11 | 12 | static const char* app_description = "\nFlashnul - flash drive tester and cleaner\nUsage: flashnul [OPTIONS]\nWarning: mostly all operations very DESTRUCTIVE and can cause a permanent information lose.\n Use carefully. Keep out of childen.\nPlease, avoid using near source of open flame.\nContra-indicated for people with reduced mental faculties.\n"; 13 | static const char* app_ver = "flashnul 1.0rc1 (ex 0.994, "__DATE__", "__TIME__")\n\n"; 14 | static const char* copyright = "\n(c) George Shuklin, 2005-2008\nLicence: GNU Public Licence\nhomepage: www.shounen.ru/soft/flashnul/\nbugs mail to: gs@shounen.ru\n"; 15 | static const char* dump_warning = "\n\nIf you do not know how to use this program, please, read readme.rus.html\n"; 16 | 17 | enum{ 18 | OPT_help, 19 | OPT_ver, 20 | OPT_fill, 21 | OPT_inc, 22 | OPT_read, 23 | OPT_blank, 24 | OPT_test, 25 | OPT_quick, 26 | OPT_update, 27 | // OPT_advanced, 28 | OPT_verify, 29 | OPT_do_not_confirm, 30 | OPT_ignore, 31 | OPT_cycle, 32 | OPT_probe, 33 | OPT_load, 34 | OPT_save, 35 | OPT_block_size, 36 | OPT_range, 37 | OPT_mode, 38 | OPT_delay, 39 | OPT_key, 40 | OPT_share, 41 | // OPT_alert, 42 | OPT_block_vendor, 43 | OPT_block_name, 44 | OPT_block_serial, 45 | OPT_block_bus, 46 | OPT_block_nonremovable, 47 | OPT_block_device, 48 | OPT_block_letter, 49 | OPT_block_number, 50 | OPT_ignore_block, 51 | OPT_title 52 | }; 53 | 54 | claOptName_t opt[]={ 55 | { OPT_help, "help", 'h', CLA_HELP, 0, 0, "display help" }, 56 | { OPT_ver, "version", 'v', CLA_HELP, 0, 0, "display version" }, 57 | { OPT_fill, "fill", 'F', CLA_TYPE_NUMBER|CLA_CMD|CLA_GROUP_0, 0, 1, "fill drive by zeroes (wipe)" }, 58 | { OPT_inc, "incremental",'I', CLA_TYPE_NUMBER|CLA_CMD|CLA_GROUP_0, 0, 1, "fill by incremented bytes (wipe)"}, 59 | { OPT_read, "read", 'R', CLA_TYPE_NUMBER|CLA_CMD|CLA_GROUP_0, 0, 0, "test drive for read (non destructive)"}, 60 | { OPT_blank, "blank", 'B', CLA_TYPE_SWITCH|CLA_CMD|CLA_GROUP_0, 0, 0, "erase a first sector (wipe)"}, 61 | { OPT_test, "test", 'T', CLA_TYPE_SWITCH|CLA_CMD|CLA_GROUP_0, 0, 0, "run standart test (-I -V=3 -m=1)"}, 62 | { OPT_quick, "quick", 'Q', CLA_TYPE_SWITCH|CLA_CMD|CLA_GROUP_0, 1, 0, "run a quick test"}, 63 | { OPT_update, "update", 'U', CLA_TYPE_SWITCH|CLA_CMD|CLA_GROUP_0, 1, 0, "update mode (write back)"}, 64 | //{ OPT_advanced, "advanced-recovery", 0, CLA_TYPE_SWITCH|CLA_CMD|CLA_GROUP_0, 1, 3, "save image from damaged media"}, 65 | { OPT_verify, "verify", 'V', CLA_NUMBER, 1, 1, "use a verification (mode = 1,2,3)"}, 66 | { OPT_do_not_confirm,"no-prompt",'P', CLA_SWITCH, 0, 0, "do not prompt about destructive functions"}, 67 | { OPT_ignore, "ignore-errors",'i', CLA_SWITCH, 0, 0, "ignore errors (do not stop after first error)"}, 68 | { OPT_cycle, "cycle", 'c', CLA_NUMBER, 1, 1, "run operation given number of loops (-R,I,F)"}, 69 | { OPT_probe, "probe", 'p', CLA_TYPE_NUMBER|CLA_CMD|CLA_GROUP_0, 0, 1, "list of avaible drives"}, 70 | { OPT_load, "load", 'L', CLA_TYPE_STRING|CLA_CMD|CLA_GROUP_0, 1, 1, "load file to drive (copy image from file to drive)"}, 71 | { OPT_save, "save", 'S', CLA_TYPE_STRING|CLA_CMD|CLA_GROUP_0, 1, 2, "save drive to file (copy image from drive to file)"}, 72 | { OPT_block_size, "block-size",'b', CLA_NUMBER, 1, 1, "set block size for read/writing (min sector size)"}, 73 | { OPT_range, "range", 'r', CLA_NUMBER, 1, 2, "set range of read/write operation (-R,S,L,I,F)"}, 74 | { OPT_mode, "mode", 'm', CLA_NUMBER, 1, 1, "change test mode for -I option"}, 75 | { OPT_delay, "delay", 'd', CLA_NUMBER, 1, 1, "delay before re-read data (-V=2,3)"}, 76 | { OPT_key, "disable-key", 'k', CLA_SWITCH, 0, 0, "do not prompt to press [Enter] at exit"}, 77 | { OPT_share, "write-share", 0, CLA_SWITCH, 1, 1, "enable share writing"}, 78 | //{ OPT_alert, "alert", 'a', CLA_SWITCH, 0, 0, "sound altert on errors (beep)"}, 79 | { OPT_block_vendor, "block-vendor", 0, CLA_TYPE_STRING|CLA_CFG, 1, 0, "block write operations by vendor name"}, 80 | { OPT_block_name, "block-name", 0, CLA_TYPE_STRING|CLA_CFG, 1, 0, "block write operations by device name"}, 81 | { OPT_block_serial, "block-serial", 0, CLA_TYPE_STRING|CLA_CFG, 1, 0, "block write operations by device serial"}, 82 | { OPT_block_bus, "block-bus", 0, CLA_TYPE_STRING|CLA_CFG, 1, 0, "block write operations by adapter bus"}, 83 | { OPT_block_nonremovable, "block-non-removable",0,CLA_TYPE_SWITCH|CLA_CFG, 0, 0, "block all non-removable devices"}, 84 | { OPT_block_device, "block-device", 0, CLA_TYPE_STRING|CLA_CFG, 1, 0, "block write by string in any field"}, 85 | { OPT_block_letter, "block-letter", 0, CLA_TYPE_STRING|CLA_CFG, 1, 0, "block write to logical drive by drive letter"}, 86 | { OPT_block_number, "block-number", 0, CLA_TYPE_NUMBER|CLA_CFG, 1, 0, "block write to physical drive by drive number"}, 87 | { OPT_ignore_block, "ignore-block", 0, CLA_TYPE_SWITCH|CLA_CMD, 1, 0, "ignore block options"}, 88 | { OPT_title, "title", 't', CLA_SWITCH, 0, 0, "use window title to show process"} 89 | }; 90 | 91 | 92 | static char* old_title; 93 | static DWORD old_title_size=0; 94 | 95 | void title_init(){ 96 | if(old_title_size) return; 97 | old_title=malloc(65535); 98 | if(!old_title){ 99 | old_title_size=0; /* size=0 - not to free at exit and no change back*/ 100 | }else{ 101 | old_title_size=65535; 102 | GetConsoleTitle(old_title,old_title_size); 103 | old_title[65534]=0;/*paranoic*/ 104 | } 105 | SetConsoleTitle(app_ver); 106 | } 107 | 108 | 109 | void title_text2 ( const char* text1, const char* text2 ){ 110 | int text_size=strlen(text1)+strlen(text2)+strlen(app_ver)+4; 111 | char* text; 112 | if( text_size > 65535 ) return; /*spec of SetConsoleTitle*/ 113 | text=malloc(text_size); 114 | if( !text && !old_title_size ) return; 115 | snprintf(text,text_size,"%s%s - %s",text1,text2,app_ver); 116 | SetConsoleTitle(text); 117 | } 118 | 119 | void title_dev_text( const char* op, dev_ctrl_t* dev ){ 120 | return; 121 | } 122 | 123 | void title_restore(){ 124 | if (old_title_size){ 125 | SetConsoleTitle(old_title); 126 | free(old_title); 127 | old_title=NULL; 128 | old_title_size=0; 129 | } 130 | } 131 | 132 | 133 | 134 | int check_substring( claCfg_t* config, int optID, char* string ){ 135 | int c; 136 | 137 | if( isactive(config,optID ) ){ 138 | for(c = 0; c< argnum( config, optID ); c++ ){ 139 | if(strstr( string, soptM( config, optID, c ) ) ) 140 | return 1; 141 | } 142 | } 143 | return 0; 144 | } 145 | 146 | static char drive_letter(char* name){ 147 | if(strlen(name)!=2) 148 | return 0; 149 | if(name[1]==':' ) 150 | return name[0]; 151 | return 0; 152 | } 153 | 154 | static int drive_number(char*name){ 155 | int l=strlen(name); 156 | int end; 157 | int c; 158 | assert(l); 159 | for(c=l-1;c;c--) 160 | if(!isdigit(name[c])){ 161 | end=c+1; 162 | break; 163 | } 164 | if( !c || c == l - 1 ) 165 | return -1; 166 | return strtol(name+end,NULL,10); 167 | } 168 | 169 | int isblocked( claCfg_t* config, dev_ctrl_t* dev){ 170 | 171 | int i; 172 | char letter; 173 | int number; 174 | 175 | if( isactive( config, OPT_ignore_block ) ) 176 | return 0; 177 | if( check_substring( config, OPT_block_vendor, dev->vendor ) ) 178 | return OPT_block_vendor; 179 | if( check_substring( config, OPT_block_name, dev->name ) ) 180 | return OPT_block_name; 181 | if( check_substring( config, OPT_block_serial, dev->serial ) ) 182 | return OPT_block_serial; 183 | if( check_substring( config, OPT_block_bus, dev->bus_name ) ) 184 | return OPT_block_bus; 185 | if( isactive(config, OPT_block_nonremovable) && !dev->removable ) 186 | return OPT_block_nonremovable; 187 | if( isactive( config, OPT_block_device ) ){ 188 | if( 189 | check_substring( config, OPT_block_device, dev->vendor ) || 190 | check_substring( config, OPT_block_device, dev->name ) || 191 | check_substring( config, OPT_block_device, dev->serial ) 192 | ) 193 | return OPT_block_device; 194 | } 195 | 196 | if( isactive( config, OPT_block_letter ) ){ 197 | letter = drive_letter( dev->user_name ); 198 | if(letter) 199 | for(i=0;iuser_name ); 209 | if(number>=0) 210 | for(i=0;iuser_name, opt[block_status].optName ); 229 | return 0; 230 | } 231 | 232 | printf("\n\tSelected operation:\t %s\n",action_name); 233 | printf("\tSelected drive:\t\t %s, %I64db (%s)\n\n", dev->user_name, dev->size, human_view( dev->size, 'b') ); 234 | 235 | if( isactive( config, OPT_do_not_confirm ) ){ 236 | result = 0; 237 | }else{ 238 | printf( "\tTHIS OPERATION IS DESTRUCTIVE!!!\n" ); 239 | printf( "\tType 'yes' to confirm operation. All other text will stop it.\n\n"); 240 | printf( "\tReally destroy data on drive %s? :",dev->user_name); 241 | 242 | fgets( reply, MAX_PATH, stdin ); 243 | 244 | for( c = 0; reply[c] && c < MAX_PATH; c++ ) 245 | reply[c] = toupper( reply[c] ); 246 | 247 | result = strncmp( reply, "YES\n", MAX_PATH ); 248 | if(result) 249 | printf( "\nAction canceled\n" ); 250 | printf("\n"); 251 | } 252 | 253 | if(!result){ 254 | print_header("[Log]"); 255 | printf("Runing operation [%s] for drive %s\n\n", action_name, dev->user_name ); 256 | } 257 | 258 | return !result; 259 | 260 | } 261 | 262 | 263 | 264 | 265 | /*global varible*/ 266 | dev_ctrl_t* selected_device; 267 | int enter_key = 1; 268 | 269 | void end_message(void){ 270 | if( selected_device ) 271 | print_footer( selected_device ); 272 | if(enter_key) 273 | wait_for_key("\n\nPress ENTER to exit. \n"); 274 | title_restore(); 275 | } 276 | 277 | 278 | static claCfg_t* read_config_file(){ 279 | 280 | #ifdef CONFIG_FILE 281 | #ifdef HOME_DIR_CONFIG 282 | char real_config[MAX_PATH+1]; 283 | char *home_dir=strdup(_pgmptr); 284 | int c; 285 | for( c=strlen(home_dir);c;c--){ 286 | if(home_dir[c]=='\\'){ 287 | home_dir[c+1]=0; 288 | break; 289 | } 290 | } 291 | strcpy(real_config,home_dir); 292 | strncat(real_config,CONFIG_FILE,MAX_PATH); 293 | free(home_dir); 294 | return ReadTextConfig( real_config, opt, CLA_FLAG_STOP_ALL_ERRORS ); 295 | #else 296 | return ReadTextConfig( CONFIG_FILE, opt, CLA_FLAG_STOP_ALL_ERRORS ); 297 | #endif 298 | #else 299 | return NULL; 300 | #endif 301 | } 302 | 303 | 304 | int main( int argc, char* argv[] ){ 305 | 306 | io_ctrl_t io_ctrl = { 0, 0, 0, 0, 0, 0, 0, 0, stdout }; 307 | claCfg_t* config = NULL; 308 | claCfg_t* command_line = NULL; 309 | claCfg_t* config_file = NULL; 310 | dev_ctrl_t* dev = NULL; 311 | int c = 0; 312 | int mode = 0; 313 | 314 | setvbuf(stdout, NULL, _IONBF, 0); 315 | setvbuf(stderr, NULL, _IONBF, 0); 316 | 317 | atexit( &end_message ); 318 | 319 | command_line = ParseCommandLine(argc, argv, opt, 0, 1, CLA_FLAG_STOP_ALL_ERRORS ); 320 | if(! command_line ) 321 | exit( -1 ); 322 | if( isactive( command_line, OPT_title ) ) 323 | title_init(); 324 | if( isactive ( command_line, OPT_ver ) ){ 325 | printf( app_ver ); 326 | enter_key = 0; 327 | claClose( command_line ); 328 | return 0; 329 | } 330 | 331 | 332 | if( isactive( command_line, OPT_probe ) ){ 333 | list_disks( nopt( command_line, OPT_probe ) ); 334 | exit(0); 335 | } 336 | 337 | if( !freeoptnum( command_line ) || isactive( command_line, OPT_help ) ){ 338 | printf( app_description ); 339 | printf( app_ver ); 340 | PrintOpt( opt, stdout ); 341 | printf( copyright ); 342 | if( !freeoptnum( command_line ) ){ 343 | printf( dump_warning ); /*for mental-reduced users, expecting something after double-clicking on program*/ 344 | } 345 | claClose( command_line ); 346 | return 0; 347 | } 348 | 349 | 350 | config_file = read_config_file( ); 351 | if( config_file ){ 352 | config = claJoin( config_file, command_line, 2, 1 ); /*config file has a higher priority than a command line*/ 353 | if( !config ) 354 | exit( -1 ); 355 | }else 356 | config = command_line; 357 | 358 | enter_key =! isactive( config, OPT_key ); 359 | SetErrorMode( SEM_NOOPENFILEERRORBOX ); 360 | 361 | mode= claGroupOpt( config, CLA_GROUP_0 ); 362 | if(!mode){ 363 | printf("No action selected\n"); 364 | return 0; 365 | } 366 | 367 | io_ctrl.start = (long long)noptM( config, OPT_range, 0 ); 368 | io_ctrl.end = (long long)noptM( config, OPT_range, 1 ); 369 | io_ctrl.ignore_error = nopt( config, OPT_ignore ); 370 | io_ctrl.block_size = nopt( config, OPT_block_size ); 371 | io_ctrl.write_share = isactive( config, OPT_share ); 372 | 373 | if(mode==OPT_test){ 374 | mode=OPT_inc; 375 | io_ctrl.verify_mode=3; 376 | io_ctrl.mode=1; 377 | io_ctrl.delay=10; 378 | } 379 | 380 | if( isactive( config, OPT_verify ) ) 381 | io_ctrl.verify_mode = nopt( config, OPT_verify ); 382 | if( isactive( config, OPT_mode ) ) 383 | io_ctrl.mode = nopt( config, OPT_mode ); 384 | if( isactive( config, OPT_delay ) ) 385 | io_ctrl.delay = nopt( config, OPT_delay ); 386 | 387 | 388 | // if ( isactive( config, OPT_advanced ) ){ 389 | // advanced_recovery( freeopt( config, 0 ), soptM( config, OPT_advanced, 0), soptM(config, OPT_advanced, 1), soptM(config, OPT_advanced, 2), &io_ctrl ); 390 | // return 0; 391 | // } 392 | 393 | dev = open_drive( freeopt( config, 0 ), 0, io_ctrl.write_share ); 394 | 395 | if( !dev ){ 396 | title_text2("Fail to open ",freeopt( config, 0 )); 397 | claClose( config ); 398 | return 1; 399 | } 400 | 401 | get_drive_info( dev, 0xFF, 0 ); /*FIX*/ 402 | title_dev_text ( "device info", dev ); 403 | display_drive_info(dev); 404 | 405 | switch(mode){ 406 | case OPT_blank: 407 | if( prompt( dev, config, "erase first sector" ) ){ 408 | selected_device = dev; 409 | blank( dev, &io_ctrl ); 410 | } 411 | break; 412 | case OPT_fill: 413 | if( prompt( dev, config, "fill sectors" ) ){ 414 | selected_device = dev; 415 | for( c = 0; c < (isactive( config, OPT_cycle )? nopt( config, OPT_cycle ) : 1); c++) 416 | fill( dev, nopt( config, OPT_fill ), &io_ctrl ); 417 | } 418 | break; 419 | case OPT_inc: 420 | if( prompt( dev, config, "write test" ) ){ 421 | selected_device = dev; 422 | for( c = 0; c < ( isactive( config, OPT_cycle )? nopt( config, OPT_cycle ) : 1); c++) 423 | inc_fill( dev, nopt( config, OPT_inc ), &io_ctrl ); 424 | } 425 | break; 426 | case OPT_read: 427 | selected_device = dev; 428 | read_test( dev, &io_ctrl ); 429 | break; 430 | case OPT_quick: 431 | if( prompt( dev, config, "quick r/w test" ) ){ 432 | selected_device = dev; 433 | quick_test( dev, &io_ctrl ); 434 | } 435 | break; 436 | case OPT_update: 437 | if( prompt( dev, config, "update (rewrite)" ) ){ 438 | selected_device = dev; 439 | update_action( dev, &io_ctrl ); 440 | } 441 | break; 442 | case OPT_load: 443 | if( prompt( dev, config, "load file content" ) ){ 444 | selected_device = dev; 445 | load_image( dev, sopt( config, OPT_load ), &io_ctrl ); 446 | } 447 | break; 448 | case OPT_save: 449 | selected_device = dev; 450 | save_image( dev, sopt( config, OPT_save ), &io_ctrl ); 451 | break; 452 | 453 | 454 | } 455 | // close_drive ( dev ); 456 | claClose ( config ); 457 | 458 | return 0; 459 | } 460 | 461 | -------------------------------------------------------------------------------- /src/flashnul.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_FLASHNUL_H 2 | #define _H_FLASHNUL_H 3 | #include 4 | #include 5 | 6 | typedef struct{ 7 | long long start; 8 | long long end; 9 | int ignore_error; 10 | int verify_mode; 11 | int block_size; 12 | int mode; 13 | int delay; 14 | int write_share; 15 | FILE* log; 16 | }io_ctrl_t; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/generate.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #define MAX_ALLOWED_BLOCK 1048576 6 | /** 7 | This module contain three functions: 8 | create_filled_block 9 | creating a block of memory filled by specified byte 10 | (block must be freed after use) 11 | 12 | create_incremental_block 13 | creating a block of incrementing bytes. 14 | 15 | **/ 16 | 17 | 18 | unsigned char* create_filled_block( long long block_size, unsigned char filler ){ 19 | 20 | unsigned char* retval; 21 | 22 | if( block_size > MAX_ALLOWED_BLOCK ) 23 | exit( printf ("requested block (%I64d bytes) is too large\n", block_size ) ); 24 | 25 | retval = malloc( (size_t)block_size ); 26 | assert( retval ); 27 | 28 | memset( retval, filler, block_size ); 29 | 30 | return retval; 31 | 32 | } 33 | 34 | unsigned char* create_incremental_block( long long offset,int sector_size, long long size,long long iterator ){ 35 | 36 | int initial_value; 37 | int c; 38 | unsigned char* retval; 39 | 40 | assert( size % sizeof(size_t) == 0 ); 41 | 42 | retval = malloc( (size_t)size ); 43 | assert( retval ); 44 | 45 | initial_value = (offset+iterator)/sizeof(int); 46 | 47 | for( c = 0; c < size / sizeof( int ); c++ ) 48 | ((int*)retval)[c] = initial_value + c; 49 | 50 | return retval; 51 | 52 | } 53 | 54 | unsigned char* create_chess_block( long long offset,int sector_size, long long size, int counter){ 55 | char *pattern1="\xFF\x0"; 56 | char *pattern2="\x0\xFF"; 57 | int c; 58 | unsigned char* retval = malloc( (size_t)size ); 59 | 60 | assert( retval ); 61 | 62 | if(size%2){ 63 | exit(printf("sorry, test pattern do not fit in block size (%I64d)\n", size)); 64 | } 65 | for(c = 0; c< size;c+=2){ 66 | if( counter % 2 ) 67 | memcpy(retval+c,pattern1,2); 68 | else 69 | memcpy(retval+c,pattern2,2); 70 | } 71 | 72 | return retval; 73 | } 74 | 75 | unsigned char* create_test_block( long long offset,int sector_size, long long size, int counter, int mode ){ 76 | 77 | if( size > MAX_ALLOWED_BLOCK ) 78 | exit( printf ("error: requested block (%I64d bytes) is too large\n", size ) ); 79 | 80 | if( !size ) 81 | exit( printf( "error: requested a block with size 0 bytes\n")); 82 | 83 | switch (mode){ 84 | case 0: 85 | return create_incremental_block( offset, sector_size, size, counter*size); 86 | case 1: 87 | return create_chess_block( offset, sector_size, size, counter); 88 | default: 89 | printf("Sorry, unsupported mode (-m=%d)\n",mode); 90 | exit(0); 91 | } 92 | return NULL; 93 | } 94 | 95 | 96 | -------------------------------------------------------------------------------- /src/generate.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_GENERATE_H 2 | #define _H_GENERATE_H 3 | unsigned char* create_filled_block( long long block_size, unsigned char filler ); 4 | unsigned char* create_test_block( long long offset,int sector_size, long long size, int counter, int mode ); 5 | unsigned char* create_incremental_block( long long offset,int sector_size, long long size, long long iterator ); 6 | #endif 7 | -------------------------------------------------------------------------------- /src/io.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "finetune.h" 10 | #include "ddk.h" 11 | #include "io.h" 12 | #include "common.h" 13 | #include "display.h" 14 | 15 | char* error_text(){ 16 | 17 | static char message[MAX_PATH*2]; 18 | LPVOID lpMsgBuf; 19 | DWORD dw = GetLastError(); 20 | 21 | FormatMessage( 22 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 23 | FORMAT_MESSAGE_FROM_SYSTEM, 24 | NULL, 25 | dw, 26 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 27 | (LPTSTR) &lpMsgBuf, 28 | 0, NULL ); 29 | 30 | CharToOem(lpMsgBuf,lpMsgBuf); 31 | strncpy(message,lpMsgBuf,MAX_PATH*2-1); 32 | LocalFree(lpMsgBuf); 33 | return message; 34 | } 35 | 36 | 37 | int get_free_space(dev_ctrl_t* dev){ 38 | 39 | char *dir = malloc( strlen( dev->system_name ) + 2 ); 40 | ULARGE_INTEGER free_avaible; 41 | ULARGE_INTEGER total; 42 | ULARGE_INTEGER free; 43 | int status; 44 | 45 | assert( dir ); 46 | strcpy( dir, dev->system_name ); 47 | strcat( dir, "\\" ); 48 | 49 | status = GetDiskFreeSpaceEx( dir,(PULARGE_INTEGER)&free_avaible, (PULARGE_INTEGER)&total, (PULARGE_INTEGER)&free ); 50 | 51 | if( status ){ 52 | dev->disk_size = (long long) total.QuadPart; 53 | dev->free_size = (long long) free.QuadPart; 54 | dev->avaible_size = (long long) free_avaible.QuadPart; 55 | } 56 | return status; 57 | 58 | } 59 | 60 | int get_drive_geometry(dev_ctrl_t* dev){ 61 | 62 | int result; 63 | DWORD junk; 64 | DISK_GEOMETRY disk_geometry; 65 | 66 | result = DeviceIoControl ( 67 | dev->device_handle, 68 | IOCTL_DISK_GET_DRIVE_GEOMETRY, 69 | NULL, 0, 70 | &disk_geometry, 71 | sizeof( DISK_GEOMETRY ), 72 | &junk, 73 | (LPOVERLAPPED) NULL 74 | ); 75 | 76 | if( result ){ 77 | 78 | dev->sector_size = (long long)disk_geometry.BytesPerSector; 79 | dev->cylinders = (long long)disk_geometry.Cylinders.QuadPart; 80 | dev->tracks_per_cylinder= (long long)disk_geometry.TracksPerCylinder; 81 | dev->sectors_per_track = (long long)disk_geometry.SectorsPerTrack; 82 | dev->geometry_size = dev->sector_size * dev->cylinders * dev->tracks_per_cylinder * dev->sectors_per_track; 83 | } 84 | return result; 85 | 86 | } 87 | 88 | char* get_full_name(char* alias){ 89 | static char buf[MAX_PATH]; 90 | int offset = 0; 91 | if(alias[0]=='\\') 92 | offset = 1; 93 | snprintf(buf,MAX_PATH,"PhysicalDrive%s",alias+offset); 94 | return buf; 95 | } 96 | 97 | 98 | void get_perfomance_frequency( dev_ctrl_t* dev ){ 99 | /*get a frequency of the high-resolution performance counter*/ 100 | 101 | LARGE_INTEGER freq; 102 | 103 | if( QueryPerformanceFrequency( &freq ) ){ 104 | dev->freq = freq.QuadPart; 105 | dev->update_counts = ( REFRESH_DELAY * dev->freq ) / 1000; 106 | }else{ 107 | printf( "Unable to obtain a sysem speed, statistic disabled. %s\n", error_text() ); 108 | dev->freq = 0; 109 | } 110 | } 111 | 112 | 113 | dev_ctrl_t* open_drive( char* device_path, int silence, int write_share){ 114 | 115 | const char prefix[] = "\\\\.\\"; 116 | char* uname; 117 | DWORD junk; 118 | dev_ctrl_t* retval = calloc( sizeof(dev_ctrl_t), 1 ); 119 | 120 | assert( retval ); 121 | 122 | if( device_path[0]=='\\' && device_path[1] == '\\' ){ 123 | retval->user_name = strdup( device_path ); 124 | retval->system_name = strdup( device_path ); 125 | } 126 | else{ 127 | if( isdigit(device_path[0]) || ( device_path[0]=='\\' && isdigit(device_path[1]) ) ){ /*aliases for \\.\PhysicalDriveX*/ 128 | uname = get_full_name( device_path ); 129 | retval->physical_flag=1; 130 | }else{ 131 | uname=device_path; 132 | retval->physical_flag=0; 133 | } 134 | retval->user_name=strdup( uname ); 135 | retval->system_name = malloc( strlen( uname ) + strlen(prefix) + 1 ); 136 | assert( retval->user_name && retval->system_name ); 137 | strcpy(retval->system_name, prefix); 138 | strcat(retval->system_name, uname ); 139 | } 140 | retval->device_handle = CreateFile( 141 | retval->system_name, 142 | GENERIC_WRITE|GENERIC_READ, 143 | FILE_SHARE_READ |(write_share?FILE_SHARE_WRITE:0), 144 | NULL, 145 | OPEN_EXISTING, 146 | 0, 147 | NULL 148 | ); 149 | 150 | if( retval->device_handle==INVALID_HANDLE_VALUE ){ 151 | if(!silence) 152 | printf("error opening drive %s (%s): %s\n",retval->user_name, retval->system_name,error_text() ); 153 | free( retval->user_name ); 154 | free( retval->system_name ); 155 | free( retval ); 156 | return NULL; 157 | } 158 | 159 | DeviceIoControl( retval->device_handle,FSCTL_ALLOW_EXTENDED_DASD_IO, NULL,0,NULL,0,&junk,NULL); 160 | 161 | retval->write_share = write_share; 162 | 163 | get_perfomance_frequency( retval ); 164 | 165 | return retval; 166 | 167 | } 168 | 169 | void close_drive(dev_ctrl_t* dev){ 170 | 171 | CloseHandle ( dev->device_handle ); 172 | free( dev->user_name ); 173 | free( dev->system_name ); 174 | free( dev->bus_name ); 175 | free( dev->name ); 176 | free( dev->vendor ); 177 | free( dev->revision ); 178 | free( dev->raw_serial ); 179 | free( dev->serial ); 180 | free( dev ); 181 | 182 | } 183 | 184 | static inline long long get_timer(){ 185 | LARGE_INTEGER counter; 186 | if(QueryPerformanceCounter(&counter)) 187 | return counter.QuadPart; 188 | else 189 | return 0; 190 | } 191 | 192 | int write_block(dev_ctrl_t* dev, long long offset,unsigned char* data, long long data_size ){ 193 | int res; 194 | DWORD write; 195 | LARGE_INTEGER move; 196 | long long begin; 197 | long long end; 198 | long long count; 199 | long long speed; /*(b/s)*/ 200 | 201 | move.QuadPart = offset; 202 | 203 | dev->counter2 = get_timer(); 204 | 205 | if(dev->counter2 - dev->counter1 > dev->update_counts || !dev->counter2 ){ 206 | clearline(); 207 | fprintf(stderr,"\rWriting 0x%I64x (%s)",offset, human_view( offset+data_size, 'b' ) ); 208 | if(dev->freq&&dev->write_counts) 209 | fprintf(stderr,", %I64d b/s", MULDIV(dev->write_bytes,dev->freq,dev->write_counts)); 210 | dev->counter1=dev->counter2; 211 | } 212 | 213 | SetFilePointerEx(dev->device_handle, move, NULL,FILE_BEGIN); 214 | begin = get_timer(); 215 | res=WriteFile( dev->device_handle, data, data_size,(LPDWORD)&write, NULL ); 216 | end = get_timer(); 217 | if( !res ){ 218 | dev->error_count++; 219 | fprintf(stderr,"\nWrite error: %s\n",error_text()); 220 | return 0; 221 | } 222 | dev->write_bytes+= write; 223 | if( dev->freq ){ 224 | count = end - begin; 225 | dev->write_counts += count; 226 | if(dev->block_size==data_size && count > 0 ){ /*skip leftover blocks*/ 227 | speed = MULDIV (write, dev->freq, count); 228 | if( speed < dev->min_write_speed || !dev->min_write_speed ) 229 | dev->min_write_speed = speed; 230 | if( speed > dev->max_write_speed ) 231 | dev->max_write_speed = speed; 232 | } 233 | } 234 | 235 | 236 | 237 | if( write!=data_size ){ 238 | dev->error_count++; 239 | fprintf( stderr,"\nerror, only %u bytes written (insead %I64d)\n",(unsigned int)write, data_size ); 240 | return 0; 241 | } 242 | return 1; 243 | } 244 | 245 | int read_block(dev_ctrl_t* dev, long long offset, unsigned char** data, long long data_size ){ 246 | 247 | int res; 248 | DWORD read; 249 | LARGE_INTEGER move; 250 | long long begin; 251 | long long end; 252 | long long count; 253 | long long speed; /*(b/s)*/ 254 | 255 | move.QuadPart = offset; 256 | 257 | dev->counter2 = get_timer(); 258 | 259 | if(dev->counter2 - dev->counter1 > dev->update_counts || !dev->counter2 ){ 260 | clearline(); 261 | fprintf(stderr, "\rReading 0x%I64x (%s)", offset, human_view(offset, 'b') ); 262 | if(dev->freq&&dev->read_counts) 263 | fprintf(stderr,", %I64d b/s", MULDIV (dev->read_bytes,dev->freq,dev->read_counts)); 264 | dev->counter1=dev->counter2; 265 | } 266 | 267 | SetFilePointerEx( dev->device_handle, move, NULL, FILE_BEGIN ); 268 | if(!*data){ 269 | *data=malloc( data_size ); 270 | assert( *data ); 271 | }; 272 | begin = get_timer(); 273 | res = ReadFile( dev->device_handle, *data, data_size, (LPDWORD)&read, NULL ); 274 | end = get_timer(); 275 | if( !res ){ 276 | dev->error_count++; 277 | fprintf(stderr,"\nRead error: %s\n",error_text()); 278 | return 0; 279 | } 280 | 281 | dev->read_bytes += read; 282 | if( dev->freq ){ 283 | count = end - begin; 284 | dev->read_counts += count; 285 | if(dev->block_size==data_size && count > 0 ){ /*skip leftover blocks*/ 286 | speed = MULDIV( read, dev->freq, count ); 287 | if( speed < dev->min_read_speed || !dev->min_read_speed ) 288 | dev->min_read_speed = speed; 289 | if( speed > dev->max_read_speed ) 290 | dev->max_read_speed = speed; 291 | } 292 | } 293 | 294 | if( read != data_size ){ 295 | dev->error_count++; 296 | fprintf (stderr,"\nerror, only %u bytes read (insead %I64d)\n",(unsigned int)read, data_size ); 297 | return 0; 298 | } 299 | 300 | return 1; 301 | 302 | } 303 | 304 | 305 | long long get_device_size(dev_ctrl_t* dev ){ 306 | /*return a real device size*/ 307 | int result; 308 | DWORD junk; 309 | long long retval; 310 | GET_LENGTH_INFORMATION length_info; 311 | result=DeviceIoControl( 312 | dev->device_handle, 313 | IOCTL_DISK_GET_LENGTH_INFO, 314 | NULL,0, 315 | &length_info, 316 | sizeof( length_info ), 317 | &junk, 318 | (LPOVERLAPPED) NULL 319 | ); 320 | if(result) 321 | retval = (long long)(length_info.Length.QuadPart); 322 | else 323 | retval = -1; 324 | return retval; 325 | 326 | 327 | } 328 | 329 | 330 | char* get_bus_name (const int bus_type){ 331 | static char* bus_names[] = { 332 | "UNKNOWN", // 0x00 333 | "SCSI", 334 | "ATAPI", 335 | "ATA", 336 | "IEEE1394", 337 | "SSA", 338 | "FIBRE", 339 | "USB", 340 | "RAID", 341 | "ISCSI", 342 | "SAS", 343 | "SATA" 344 | }; 345 | if(bus_type<0||bus_type>=sizeof(bus_names)/sizeof(*bus_names)) 346 | return strdup(bus_names[0]); 347 | return strdup(bus_names[bus_type]); 348 | 349 | } 350 | 351 | char* get_name (const char* buffer, int text_offset,int max_len){ 352 | char* ret; 353 | if(!text_offset) 354 | return ""; 355 | ret=malloc(max_len-text_offset+1); 356 | strncpy(ret,buffer+text_offset,max_len-text_offset); 357 | ret[max_len-text_offset]=0; 358 | 359 | return ret; 360 | } 361 | 362 | 363 | void remove_trail_spaces(char* line){ 364 | int c; 365 | for(c=strlen(line)-1;c;c--){ 366 | if(line[c]==' '||line[c]=='\t') 367 | line[c]=0; 368 | else 369 | break; 370 | } 371 | } 372 | 373 | char* clean_serial( const char* serial ){ 374 | #define HEX(a) (isalpha(a)?(isupper(a)?(a-'A'+10):(a-'a'+10)):(a-'0')) 375 | int len = strlen(serial); 376 | int c; 377 | char* newline; 378 | int endline=0; 379 | 380 | for( c = 0; c < len; c++ ){ 381 | endline=c; 382 | if( !isxdigit(serial[c]) && !isdigit(serial[c]) ) 383 | break; 384 | 385 | } 386 | endline = (endline+1)&0xFFFFFFFC; /*making multipy to 4*/ 387 | 388 | if( !endline ) 389 | return strdup( serial ); 390 | 391 | 392 | newline = malloc( len - endline/2 + 3 );/* len(newline)=len(decoded serial)+len(leftover)+3*/ 393 | assert( newline ); 394 | 395 | for( c = 0; c < endline; c += 4 ){ 396 | newline[c/2] = HEX(serial[c+2])*16+HEX(serial[c+3]); 397 | newline[c/2+1] = HEX(serial[c])*16+HEX(serial[c+1]); 398 | } 399 | 400 | newline[c/2] = 0; 401 | 402 | remove_trail_spaces(newline); 403 | 404 | if(endline!=len){ 405 | strcat( newline, " /" ); 406 | strcat( newline, serial + endline ); 407 | } 408 | 409 | return newline; 410 | } 411 | 412 | 413 | int get_adapter_property( dev_ctrl_t* dev ){ 414 | 415 | #define BUFFER_SIZE 2047 416 | 417 | STORAGE_PROPERTY_QUERY query; 418 | BOOL status; 419 | UCHAR buffer[BUFFER_SIZE+1]; 420 | ULONG returned_length; 421 | 422 | query.PropertyId = StorageAdapterProperty; 423 | query.QueryType = PropertyStandardQuery; 424 | 425 | status = DeviceIoControl(dev->device_handle, 426 | IOCTL_STORAGE_QUERY_PROPERTY, 427 | &query, 428 | sizeof( STORAGE_PROPERTY_QUERY ), 429 | &buffer, 430 | BUFFER_SIZE, 431 | &returned_length, 432 | NULL 433 | ); 434 | 435 | if (status ) { 436 | dev->bus_type = ( (PSTORAGE_ADAPTER_DESCRIPTOR)buffer )->BusType; 437 | dev->bus_name = get_bus_name( dev->bus_type ); 438 | }else 439 | dev->bus_name = strdup( "(error while detecting)" ); 440 | 441 | return status; 442 | 443 | } 444 | 445 | 446 | int get_device_property( dev_ctrl_t* dev ){ 447 | 448 | STORAGE_PROPERTY_QUERY query; 449 | PSTORAGE_DEVICE_DESCRIPTOR device; 450 | BOOL status; 451 | UCHAR buffer[BUFFER_SIZE+1]; 452 | ULONG returned_length; 453 | 454 | 455 | query.PropertyId = StorageDeviceProperty; 456 | query.QueryType = PropertyStandardQuery; 457 | 458 | status = DeviceIoControl( 459 | dev->device_handle, 460 | IOCTL_STORAGE_QUERY_PROPERTY, 461 | &query, 462 | sizeof( STORAGE_PROPERTY_QUERY ), 463 | &buffer, 464 | BUFFER_SIZE, 465 | &returned_length, 466 | NULL 467 | ); 468 | 469 | if ( status ) { 470 | 471 | device = (PSTORAGE_DEVICE_DESCRIPTOR) buffer; 472 | 473 | dev->removable = device->RemovableMedia; 474 | dev->CQ = device->CommandQueueing; 475 | dev->vendor = get_name(buffer,device->VendorIdOffset,returned_length); 476 | dev->name = get_name(buffer,device->ProductIdOffset,returned_length); 477 | dev->revision = get_name(buffer,device->ProductRevisionOffset,returned_length); 478 | dev->raw_serial = get_name(buffer,device->SerialNumberOffset,returned_length); 479 | dev->serial = clean_serial(dev->raw_serial); 480 | }else{ 481 | dev->vendor = strdup( "" ); 482 | dev->name = strdup( "" ); 483 | dev->revision = strdup( "" ); 484 | dev->raw_serial = strdup( "" ); 485 | dev->serial = strdup( "" ); 486 | 487 | } 488 | 489 | return status; 490 | 491 | } 492 | 493 | 494 | int get_device_hotplug_info (dev_ctrl_t* dev ){ 495 | OSVERSIONINFOEX version; 496 | STORAGE_HOTPLUG_INFO stor; 497 | BOOL status; 498 | DWORD trash; 499 | 500 | version.dwOSVersionInfoSize=sizeof(version); 501 | 502 | status = GetVersionEx( (LPOSVERSIONINFO )&version ); 503 | if(!status) 504 | return 0; /*error*/ 505 | 506 | if(version.dwMajorVersion < 5 ) /*winNT*/ 507 | return 1; /*not a error, but no info avaible*/ 508 | 509 | if(version.dwMajorVersion == 5 && version.dwMinorVersion == 0 ) /*win2k*/ 510 | return 1; /*not a error, but no info avaible*/ 511 | 512 | /*ok, wXP, vista or higher*/ 513 | 514 | status = DeviceIoControl( 515 | dev->device_handle, 516 | IOCTL_STORAGE_GET_HOTPLUG_INFO, 517 | NULL, 518 | 0, 519 | &stor, 520 | sizeof(stor), 521 | &trash, 522 | NULL 523 | ); 524 | 525 | if(!status) 526 | return 0; /*error*/ 527 | 528 | dev->hotplug_info_flag = 1; 529 | dev->media_hotplug = stor.MediaHotplug; 530 | dev->device_hotplug = stor.DeviceHotplug; 531 | 532 | return 1; 533 | 534 | } 535 | -------------------------------------------------------------------------------- /src/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _H_IO_H 2 | #define _H_IO_H 3 | #include 4 | 5 | typedef struct{ 6 | 7 | HANDLE device_handle; /*handle to open drive */ 8 | int write_share; /*write share flag (1 - write share enabled)*/ 9 | int physical_flag; /*opened device is a physical device =1, 0 - logical */ 10 | char* user_name; /*name of device from command line*/ 11 | char* system_name; /*name of device, as passed to CreateFile() */ 12 | long long size; /*device size (collected from diff.sources) */ 13 | long long block_size; /*size of the r/w block*/ 14 | 15 | /*reported from IOCTL_DISK_GET_DRIVE_GEOMETRY */ 16 | int drive_geometry_flag; 17 | long long sector_size; 18 | long long cylinders; 19 | long long tracks_per_cylinder; 20 | long long sectors_per_track; 21 | long long geometry_size; /*note: not a real size*/ 22 | 23 | /*reported from GetDiskFreeSpaceEx()*/ 24 | int disk_space_flag; 25 | long long disk_size; 26 | long long free_size; 27 | long long avaible_size; 28 | 29 | /*reported from IOCTL_DISK_GET_LENGTH_INFO*/ 30 | int drive_length_flag; 31 | long long device_size; /*most trusted value*/ 32 | 33 | /*reported from IOCTL_STORAGE_QUERY_PROPERTY (adapter)*/ 34 | int adapter_flag; 35 | int bus_type; 36 | char* bus_name; 37 | 38 | /*reported from IOCTL_STORAGE_QUERY_PROPERTY (device)*/ 39 | int device_flag; 40 | int removable; 41 | int CQ; /*NCQ, TCQ, ect*/ 42 | char* vendor; 43 | char* name; 44 | char* revision; 45 | char* raw_serial; 46 | char* serial; 47 | 48 | /*reported from IOCTL_STORAGE_GET_HOTPLUG_INFO (XP, Vista or higher)*/ 49 | int hotplug_info_flag; 50 | int media_hotplug; 51 | int device_hotplug; 52 | 53 | /*statistic*/ 54 | long long freq; /*timer freq*/ 55 | long long update_counts; /*number of counts for screen update*/ 56 | long long counter1; 57 | long long counter2; 58 | long long read_bytes; 59 | long long write_bytes; 60 | long long read_counts; /*counts of timer for read operations*/ 61 | long long write_counts; /*counts of timer for write operations*/ 62 | long long min_read_speed; 63 | long long min_write_speed; 64 | long long max_read_speed; 65 | long long max_write_speed; 66 | 67 | 68 | long long error_count; 69 | long long pass_count; 70 | int detection_error; /*error in detection*/ 71 | 72 | 73 | }dev_ctrl_t; 74 | 75 | 76 | 77 | char* error_text(); 78 | 79 | dev_ctrl_t* open_drive( char* device_path, int silence, int write_share ); 80 | void close_drive( dev_ctrl_t* dev ); 81 | 82 | int get_free_space( dev_ctrl_t* dev ); 83 | int get_drive_geometry( dev_ctrl_t* dev ); 84 | 85 | int get_device_property( dev_ctrl_t* dev); 86 | int get_adapter_property( dev_ctrl_t* dev ); 87 | 88 | long long get_device_size( dev_ctrl_t* dev ); 89 | int get_device_hotplug_info (dev_ctrl_t* dev ); 90 | 91 | int read_block(dev_ctrl_t* dev, long long offset, unsigned char** data, long long data_size ); 92 | int write_block(dev_ctrl_t* dev, long long offset,unsigned char* data, long long data_size ); 93 | void list_disks(); 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /src/sample: -------------------------------------------------------------------------------- 1 | #verify=0 2 | # verify: use a verification (mode = 1,2,3) 3 | 4 | #no-prompt=0 5 | # no-prompt: do not prompt about destructive functions 6 | 7 | #ignore-errors=0 8 | # ignore-errors: ignore errors (do not stop after first error) 9 | 10 | #cycle=0 11 | # cycle: run operation given number of loops (-R,I,F) 12 | 13 | -------------------------------------------------------------------------------- /todo: -------------------------------------------------------------------------------- 1 | version 1 has been stopped (only bugfixes before release) 2 | 3 | version 2 (roadmap): 4 | * creating partition table, changing attributes (boot, fs type) 5 | * formating of partition (no sure..., may be by exec of 'format'?) 6 | * unpaking builtin image of DOS in winNT/2k/XP 7 | allowing to make boot flash without MSDOS files not only on flash) 8 | 9 | v 3 (long long way to go) 10 | * advanced raw recovery (contintue reding after device replugging after fault) 11 | --------------------------------------------------------------------------------