├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile.am ├── NEWS ├── README.md ├── TODO ├── autogen.sh ├── configure.ac └── src ├── Makefile.am ├── gcfs.c ├── gcfs.h ├── main.c ├── tree.c └── tree.h /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | Makefile.in 3 | config.log 4 | config.status 5 | *.o 6 | gcfuse 7 | aclocal.m4 8 | compile 9 | configure 10 | depcomp 11 | install-sh 12 | missing 13 | .deps 14 | config.h 15 | config.h.in 16 | stamp-h1 17 | autom4te.cache 18 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Mike Melanson 2 | 3 | based on Fusepak by: 4 | Janusz Dziemidowicz 5 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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 | 294 | Copyright (C) 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 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 0.9.1: 2 | * copy whole title into .metadata (only 32 characters made it before) 3 | * make main .DOL executable available to browse in the root directory 4 | 5 | 0.9: 6 | * initial release 7 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free 5 | Software Foundation, Inc. 6 | 7 | This file is free documentation; the Free Software Foundation gives 8 | unlimited permission to copy, distribute and modify it. 9 | 10 | Basic Installation 11 | ================== 12 | 13 | These are generic installation instructions. 14 | 15 | The `configure' shell script attempts to guess correct values for 16 | various system-dependent variables used during compilation. It uses 17 | those values to create a `Makefile' in each directory of the package. 18 | It may also create one or more `.h' files containing system-dependent 19 | definitions. Finally, it creates a shell script `config.status' that 20 | you can run in the future to recreate the current configuration, and a 21 | file `config.log' containing compiler output (useful mainly for 22 | debugging `configure'). 23 | 24 | It can also use an optional file (typically called `config.cache' 25 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 26 | the results of its tests to speed up reconfiguring. (Caching is 27 | disabled by default to prevent problems with accidental use of stale 28 | cache files.) 29 | 30 | If you need to do unusual things to compile the package, please try 31 | to figure out how `configure' could check whether to do them, and mail 32 | diffs or instructions to the address given in the `README' so they can 33 | be considered for the next release. If you are using the cache, and at 34 | some point `config.cache' contains results you don't want to keep, you 35 | may remove or edit it. 36 | 37 | The file `configure.ac' (or `configure.in') is used to create 38 | `configure' by a program called `autoconf'. You only need 39 | `configure.ac' if you want to change it or regenerate `configure' using 40 | a newer version of `autoconf'. 41 | 42 | The simplest way to compile this package is: 43 | 44 | 1. `cd' to the directory containing the package's source code and type 45 | `./configure' to configure the package for your system. If you're 46 | using `csh' on an old version of System V, you might need to type 47 | `sh ./configure' instead to prevent `csh' from trying to execute 48 | `configure' itself. 49 | 50 | Running `configure' takes awhile. While running, it prints some 51 | messages telling which features it is checking for. 52 | 53 | 2. Type `make' to compile the package. 54 | 55 | 3. Optionally, type `make check' to run any self-tests that come with 56 | the package. 57 | 58 | 4. Type `make install' to install the programs and any data files and 59 | documentation. 60 | 61 | 5. You can remove the program binaries and object files from the 62 | source code directory by typing `make clean'. To also remove the 63 | files that `configure' created (so you can compile the package for 64 | a different kind of computer), type `make distclean'. There is 65 | also a `make maintainer-clean' target, but that is intended mainly 66 | for the package's developers. If you use it, you may have to get 67 | all sorts of other programs in order to regenerate files that came 68 | with the distribution. 69 | 70 | Compilers and Options 71 | ===================== 72 | 73 | Some systems require unusual options for compilation or linking that the 74 | `configure' script does not know about. Run `./configure --help' for 75 | details on some of the pertinent environment variables. 76 | 77 | You can give `configure' initial values for configuration parameters 78 | by setting variables in the command line or in the environment. Here 79 | is an example: 80 | 81 | ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix 82 | 83 | *Note Defining Variables::, for more details. 84 | 85 | Compiling For Multiple Architectures 86 | ==================================== 87 | 88 | You can compile the package for more than one kind of computer at the 89 | same time, by placing the object files for each architecture in their 90 | own directory. To do this, you must use a version of `make' that 91 | supports the `VPATH' variable, such as GNU `make'. `cd' to the 92 | directory where you want the object files and executables to go and run 93 | the `configure' script. `configure' automatically checks for the 94 | source code in the directory that `configure' is in and in `..'. 95 | 96 | If you have to use a `make' that does not support the `VPATH' 97 | variable, you have to compile the package for one architecture at a 98 | time in the source code directory. After you have installed the 99 | package for one architecture, use `make distclean' before reconfiguring 100 | for another architecture. 101 | 102 | Installation Names 103 | ================== 104 | 105 | By default, `make install' will install the package's files in 106 | `/usr/local/bin', `/usr/local/man', etc. You can specify an 107 | installation prefix other than `/usr/local' by giving `configure' the 108 | option `--prefix=PREFIX'. 109 | 110 | You can specify separate installation prefixes for 111 | architecture-specific files and architecture-independent files. If you 112 | give `configure' the option `--exec-prefix=PREFIX', the package will 113 | use PREFIX as the prefix for installing programs and libraries. 114 | Documentation and other data files will still use the regular prefix. 115 | 116 | In addition, if you use an unusual directory layout you can give 117 | options like `--bindir=DIR' to specify different values for particular 118 | kinds of files. Run `configure --help' for a list of the directories 119 | you can set and what kinds of files go in them. 120 | 121 | If the package supports it, you can cause programs to be installed 122 | with an extra prefix or suffix on their names by giving `configure' the 123 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 124 | 125 | Optional Features 126 | ================= 127 | 128 | Some packages pay attention to `--enable-FEATURE' options to 129 | `configure', where FEATURE indicates an optional part of the package. 130 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 131 | is something like `gnu-as' or `x' (for the X Window System). The 132 | `README' should mention any `--enable-' and `--with-' options that the 133 | package recognizes. 134 | 135 | For packages that use the X Window System, `configure' can usually 136 | find the X include and library files automatically, but if it doesn't, 137 | you can use the `configure' options `--x-includes=DIR' and 138 | `--x-libraries=DIR' to specify their locations. 139 | 140 | Specifying the System Type 141 | ========================== 142 | 143 | There may be some features `configure' cannot figure out automatically, 144 | but needs to determine by the type of machine the package will run on. 145 | Usually, assuming the package is built to be run on the _same_ 146 | architectures, `configure' can figure that out, but if it prints a 147 | message saying it cannot guess the machine type, give it the 148 | `--build=TYPE' option. TYPE can either be a short name for the system 149 | type, such as `sun4', or a canonical name which has the form: 150 | 151 | CPU-COMPANY-SYSTEM 152 | 153 | where SYSTEM can have one of these forms: 154 | 155 | OS KERNEL-OS 156 | 157 | See the file `config.sub' for the possible values of each field. If 158 | `config.sub' isn't included in this package, then this package doesn't 159 | need to know the machine type. 160 | 161 | If you are _building_ compiler tools for cross-compiling, you should 162 | use the `--target=TYPE' option to select the type of system they will 163 | produce code for. 164 | 165 | If you want to _use_ a cross compiler, that generates code for a 166 | platform different from the build platform, you should specify the 167 | "host" platform (i.e., that on which the generated programs will 168 | eventually be run) with `--host=TYPE'. 169 | 170 | Sharing Defaults 171 | ================ 172 | 173 | If you want to set default values for `configure' scripts to share, you 174 | can create a site shell script called `config.site' that gives default 175 | values for variables like `CC', `cache_file', and `prefix'. 176 | `configure' looks for `PREFIX/share/config.site' if it exists, then 177 | `PREFIX/etc/config.site' if it exists. Or, you can set the 178 | `CONFIG_SITE' environment variable to the location of the site script. 179 | A warning: not all `configure' scripts look for a site script. 180 | 181 | Defining Variables 182 | ================== 183 | 184 | Variables not defined in a site shell script can be set in the 185 | environment passed to `configure'. However, some packages may run 186 | configure again during the build, and the customized values of these 187 | variables may be lost. In order to avoid this problem, you should set 188 | them in the `configure' command line, using `VAR=value'. For example: 189 | 190 | ./configure CC=/usr/local2/bin/gcc 191 | 192 | causes the specified `gcc' to be used as the C compiler (unless it is 193 | overridden in the site shell script). Here is a another example: 194 | 195 | /bin/bash ./configure CONFIG_SHELL=/bin/bash 196 | 197 | Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent 198 | configuration-related scripts to be executed by `/bin/bash'. 199 | 200 | `configure' Invocation 201 | ====================== 202 | 203 | `configure' recognizes the following options to control how it operates. 204 | 205 | `--help' 206 | `-h' 207 | Print a summary of the options to `configure', and exit. 208 | 209 | `--version' 210 | `-V' 211 | Print the version of Autoconf used to generate the `configure' 212 | script, and exit. 213 | 214 | `--cache-file=FILE' 215 | Enable the cache: use and save the results of the tests in FILE, 216 | traditionally `config.cache'. FILE defaults to `/dev/null' to 217 | disable caching. 218 | 219 | `--config-cache' 220 | `-C' 221 | Alias for `--cache-file=config.cache'. 222 | 223 | `--quiet' 224 | `--silent' 225 | `-q' 226 | Do not print messages saying which checks are being made. To 227 | suppress all normal output, redirect it to `/dev/null' (any error 228 | messages will still be shown). 229 | 230 | `--srcdir=DIR' 231 | Look for the package's source code in directory DIR. Usually 232 | `configure' can determine that directory automatically. 233 | 234 | `configure' also accepts some other, not widely useful, options. Run 235 | `configure --help' for more details. 236 | 237 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src 2 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | release 1.0 2 | * initial release 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gcfuse - Use FUSE To Mount GameCube Filesystems 2 | 3 | gcfuse is a program that allows you to mount a Nintendo GameCube DVD 4 | disk image as a read-only part of the Linux filesystem. This allows the 5 | user to browse the directory structure and read the files within. 6 | Further, gcfuse provides access to the main program .dol and also 7 | creates a special file called .metadata in the root directory of 8 | the mounted filesystem. 9 | 10 | gcfuse accomplishes all this using Filesystem in Userspace (FUSE), 11 | available at: 12 | 13 | https://github.com/libfuse/libfuse 14 | 15 | Note that it is not usually possible to simply read a Nintendo optical discs in 16 | an ordinary computer's DVD-ROM drive. In order to 17 | mount a filesystem, generally, you will have to rip the proper 18 | sector image from the disc using special hardware and tools, or contact 19 | another source who has already done so. 20 | 21 | Note also that there are likely to be bugs and perhaps even security 22 | problems. It is currently meant as primarily an experimental research 23 | tool for studying GameCube discs. 24 | 25 | ### Requirements: 26 | - Linux 2.4.x or 2.6.x (as of 2.6.14 FUSE is part of the kernel, but you still need user libraries) 27 | - FUSE (http://fuse.sourceforge.net) 2.5.x or higher 28 | - FUSE development libraries; 'libfuse-dev' on Ubuntu distros 29 | 30 | ### Build: 31 | ./autogen.sh 32 | ./configure 33 | make 34 | 35 | ### Install: 36 | make install 37 | 38 | #### Usage: 39 | The basic usage is to supply a Nintendo GameCube disc image and an empty mount point on the filesystem: 40 | 41 | gcfuse 42 | 43 | Browsing to the mount point will reveal the directory structure of the disc's filesystems. Further, 44 | it will also expose the root executable .dol file, which is an implicit part of the disc filesystem. 45 | This file will be named after the name of the disc. 46 | 47 | Speaking of the name of the disc, the filesystem will also have a '.metadata' file at the root which 48 | contains a few bits of metadata embedded in the filesystem, including: 49 | - Game code 50 | - Publisher code 51 | - Title 52 | 53 | The filesystem derives the name of the root executable from that title metadata. 54 | 55 | To unmount previously mounted file, use: 56 | fusermount -u 57 | 58 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - more metadata 2 | - make the program more solid and secure 3 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | aclocal && autoheader && autoconf && automake --add-missing 2 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([gcfuse], [0.9.1], [mike@multimedia.cx]) 2 | AM_INIT_AUTOMAKE([1.11 foreign]) 3 | AC_CONFIG_HEADER([src/config.h]) 4 | 5 | AC_PROG_CC 6 | 7 | CPPFLAGS="$CPPFLAGS -Wall `getconf LFS_CFLAGS`" 8 | LDFLAGS="$LDFLAGS `getconf LFS_LDFLAGS`" 9 | 10 | PKG_CHECK_MODULES([FUSE], [fuse >= 2.5]) 11 | 12 | AC_C_CONST 13 | 14 | AC_FUNC_MALLOC 15 | AC_FUNC_STAT 16 | 17 | AC_CONFIG_FILES([Makefile src/Makefile]) 18 | AC_OUTPUT 19 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = gcfuse 2 | gcfuse_SOURCES = tree.c gcfs.c main.c 3 | noinst_HEADERS = tree.h gcfs.h 4 | gcfuse_CFLAGS = $(CFLAGS) $(FUSE_CFLAGS) 5 | gcfuse_LDADD = $(LDFLAGS) $(FUSE_LDFLAGS) $(FUSE_LIBS) 6 | -------------------------------------------------------------------------------- /src/gcfs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 Mike Melanson (mike at multimedia.cx) 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | */ 18 | 19 | /*! 20 | * \file gcfs.c 21 | * \author Mike Melanson 22 | * \brief Interpret the Nintendo GameCube filesystem 23 | */ 24 | 25 | #include 26 | 27 | #include "tree.h" 28 | #include "gcfs.h" 29 | 30 | #define NAME_MAX_SIZE 1024 31 | #define METADATA_FILE_NAME ".metadata" 32 | #define CRLF "\x0D\x0A" 33 | 34 | // the filename is a slight variation of game name with "-exe.dol" tacked 35 | // on the end; the game name can be at most 0x3E0, with 9 bytes for the 36 | // extended string + NULL; round out to 0x400 37 | #define MAX_MAIN_DOL_FILENAME_SIZE 0x400 38 | 39 | // global file description since main program needs to access it 40 | int gcfs_fd; 41 | 42 | //! Extract \c gcfsfile structure from FUSE context. 43 | static inline struct gcfsfile *get_gcfsfile_from_context(void) 44 | { 45 | return (struct gcfsfile *)fuse_get_context()->private_data; 46 | } 47 | 48 | // ********************************************************************** 49 | // gcfs operations 50 | // ********************************************************************** 51 | 52 | // ********************************************************************** 53 | // FUSE operations 54 | // Here comes FUSE operations, please consult fuse.h for description of 55 | // each operation. 56 | // ********************************************************************** 57 | 58 | /*! 59 | * \brief Get file attributes. 60 | */ 61 | static int gcfs_getattr(const char *path, struct stat *stbuf) 62 | { 63 | struct stat st; 64 | 65 | // special handling for the metadata file 66 | if (strcmp(path + 1, METADATA_FILE_NAME) == 0) { 67 | memset(stbuf, 0, sizeof(struct stat)); 68 | // Set UID and GID to current user 69 | stbuf->st_uid = getuid(); 70 | stbuf->st_gid = getgid(); 71 | stbuf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; 72 | stbuf->st_nlink = 1; 73 | stbuf->st_size = get_gcfsfile_from_context()->metadata_size; 74 | // Set all times to the values from PACK file. 75 | fstat(get_gcfsfile_from_context()->fd, &st); 76 | stbuf->st_atime = st.st_atime; 77 | stbuf->st_mtime = st.st_mtime; 78 | stbuf->st_ctime = st.st_ctime; 79 | return 0; 80 | } else 81 | return tree_getattr(path, stbuf, get_gcfsfile_from_context()->tree, 82 | get_gcfsfile_from_context()->fd); 83 | } 84 | 85 | /*! 86 | * \brief File open operation. 87 | */ 88 | static int gcfs_open(const char *path, struct fuse_file_info *fi) 89 | { 90 | // special handling for the metadata file 91 | if (strcmp(path + 1, METADATA_FILE_NAME) == 0) 92 | return 0; 93 | else 94 | return tree_open(path, fi, get_gcfsfile_from_context()->tree); 95 | } 96 | 97 | /*! 98 | * \brief Read data from an open file. 99 | */ 100 | static int gcfs_read(const char *path, char *buf, size_t size, 101 | off_t offset, struct fuse_file_info *fi) 102 | { 103 | // special handling for the metadata file 104 | if (strcmp(path + 1, METADATA_FILE_NAME) == 0) { 105 | if (offset >= get_gcfsfile_from_context()->metadata_size) 106 | return 0; 107 | 108 | if (offset + size >= get_gcfsfile_from_context()->metadata_size) 109 | size = get_gcfsfile_from_context()->metadata_size - offset; 110 | 111 | pthread_mutex_lock(&get_gcfsfile_from_context()->mutex); 112 | memcpy(buf, get_gcfsfile_from_context()->metadata, size); 113 | pthread_mutex_unlock(&get_gcfsfile_from_context()->mutex); 114 | 115 | return size; 116 | } else 117 | return tree_read(path, buf, size, offset, fi, 118 | get_gcfsfile_from_context()->tree, 119 | get_gcfsfile_from_context()->fd, 120 | &get_gcfsfile_from_context()->mutex); 121 | } 122 | 123 | /*! 124 | * Open directory. 125 | */ 126 | static int gcfs_opendir(const char *path, struct fuse_file_info *fi) 127 | { 128 | return tree_opendir(path, fi, get_gcfsfile_from_context()->tree); 129 | } 130 | 131 | /*! 132 | * \brief Read directory. 133 | */ 134 | static int gcfs_readdir(const char *path, void *buf, 135 | fuse_fill_dir_t filler, off_t offset, 136 | struct fuse_file_info *fi) 137 | { 138 | return tree_readdir(path, buf, filler, offset, fi, 139 | get_gcfsfile_from_context()->tree); 140 | } 141 | 142 | /*! 143 | * \brief Recurse through a directory structure. 144 | */ 145 | static int gcfs_recurse_directory( 146 | unsigned char *buffer, 147 | int starting_index, 148 | int ending_index, 149 | char *name_buffer, 150 | int starting_name_index, 151 | int fd, 152 | off_t filename_base_offset, 153 | struct tree *root) 154 | { 155 | int i; 156 | unsigned int filename_offset; 157 | unsigned int file_offset; 158 | unsigned int file_size; 159 | int is_dir; 160 | int name_index; 161 | char name_buffer_copy[NAME_MAX_SIZE]; 162 | 163 | fprintf (stderr, "*** recursing directory %s @ %d, recurse from %d -> %d\n", 164 | name_buffer, starting_index - 1, starting_index, ending_index); 165 | 166 | for (i = starting_index; i <= ending_index; i++) { 167 | filename_offset = BE_32(&buffer[(i-1) * 12 + 0]); 168 | file_offset = BE_32(&buffer[(i-1) * 12 + 4]); 169 | file_size = BE_32(&buffer[(i-1) * 12 + 8]); 170 | 171 | is_dir = filename_offset & 0x01000000; 172 | filename_offset &= ~0x01000000; 173 | filename_offset += filename_base_offset; 174 | 175 | // get the filename 176 | lseek(fd, filename_offset, SEEK_SET); 177 | name_index = starting_name_index; 178 | do { 179 | read(fd, name_buffer + name_index, 1); 180 | } while (isprint(name_buffer[name_index]) && 181 | (name_index++ < NAME_MAX_SIZE - 1)); 182 | // make sure the string is NULL-terminated 183 | name_buffer[name_index] = 0; 184 | 185 | if (is_dir) { 186 | name_buffer[name_index++] = '/'; 187 | name_buffer[name_index] = 0; 188 | i += gcfs_recurse_directory(buffer, i + 1, file_size, 189 | name_buffer, name_index, fd, filename_base_offset, 190 | root); 191 | } else { 192 | fprintf(stderr, "entry %d: %s; %d bytes, starts @ 0x%X\n", 193 | i, name_buffer, file_size, file_offset); 194 | memcpy(name_buffer_copy, name_buffer, NAME_MAX_SIZE); 195 | tree_insert(root, name_buffer_copy, strlen(name_buffer_copy), 196 | file_offset, file_size); 197 | } 198 | } 199 | 200 | return ending_index - starting_index + 1; 201 | } 202 | 203 | /*! 204 | * \brief Support function that returns a publisher's name. 205 | */ 206 | static char *gamecube_publisher_name(char c1, char c2) 207 | { 208 | if ((c1 == '0') && (c2 == '1')) 209 | return "Nintendo"; 210 | else if ((c1 == '0') && (c2 == '8')) 211 | return "Capcom"; 212 | else if ((c1 == '4') && (c2 == '1')) 213 | return "Ubisoft"; 214 | else if ((c1 == '4') && (c2 == 'F')) 215 | return "Eidos"; 216 | else if ((c1 == '5') && (c2 == '1')) 217 | return "Acclaim"; 218 | else if ((c1 == '5') && (c2 == '2')) 219 | return "Activision"; 220 | else if ((c1 == '5') && (c2 == 'D')) 221 | return "Midway"; 222 | else if ((c1 == '5') && (c2 == 'G')) 223 | return "Hudson"; 224 | else if ((c1 == '6') && (c2 == '4')) 225 | return "LucasArts"; 226 | else if ((c1 == '6') && (c2 == '9')) 227 | return "Electronic Arts"; 228 | else if ((c1 == '6') && (c2 == 'S')) 229 | return "TDK Mediactive"; 230 | else if ((c1 == '8') && (c2 == 'P')) 231 | return "Sega"; 232 | else if ((c1 == 'A') && (c2 == '4')) 233 | return "Mirage Studios"; 234 | else if ((c1 == 'A') && (c2 == 'F')) 235 | return "Namco"; 236 | else if ((c1 == 'B') && (c2 == '2')) 237 | return "Bandai"; 238 | else if ((c1 == 'D') && (c2 == 'A')) 239 | return "Tomy"; 240 | else if ((c1 == 'E') && (c2 == 'M')) 241 | return "Konami"; 242 | else 243 | return "unknown publisher"; 244 | } 245 | 246 | /*! 247 | * \brief Initialize filesystem. 248 | */ 249 | static void *gcfs_init(void) 250 | { 251 | int i, j; 252 | char c; 253 | unsigned char workspace[0x440]; 254 | unsigned int fst_chunk; 255 | int file_record_count; 256 | int file_records_size; 257 | unsigned char *file_records; 258 | off_t filename_base_offset; 259 | char name_buffer[NAME_MAX_SIZE]; 260 | char main_dol_filename[MAX_MAIN_DOL_FILENAME_SIZE]; 261 | unsigned int main_dol_offset; 262 | unsigned char dol_header[256]; 263 | unsigned int max_dol_section_offset; 264 | unsigned int section_offset; 265 | unsigned int section_size; 266 | 267 | struct gcfsfile *gcfs = (struct gcfsfile *)malloc(sizeof(struct gcfsfile)); 268 | if (!gcfs) { 269 | fprintf(stderr,"not enough memory\n"); 270 | close(gcfs_fd); 271 | fuse_exit(fuse_get_context()->fuse); 272 | return NULL; 273 | } 274 | 275 | gcfs->fd = gcfs_fd; 276 | // Read 64 ID bytes from the front of the resource 277 | if (read(gcfs->fd, workspace, 0x440) != 0x440) { 278 | fprintf(stderr, "file too small to be a GCFS file\n"); 279 | close(gcfs->fd); 280 | free(gcfs); 281 | fuse_exit(fuse_get_context()->fuse); 282 | return NULL; 283 | } 284 | 285 | gcfs->size = lseek(gcfs->fd, 0, SEEK_END); 286 | 287 | pthread_mutex_init(&gcfs->mutex, NULL); 288 | 289 | gcfs->tree = tree_empty(); 290 | 291 | // load the metadata 292 | gcfs->metadata[0] = 0; 293 | strcat(gcfs->metadata, "Game code: "); 294 | gcfs->metadata_size = strlen(gcfs->metadata); 295 | for (i = 0; i < 4; i++) 296 | gcfs->metadata[gcfs->metadata_size++] = 297 | isprint(workspace[i]) ? workspace[i] : '?'; 298 | strncat(gcfs->metadata, CRLF, strlen(CRLF)); 299 | strcat(gcfs->metadata, "Publisher code: "); 300 | gcfs->metadata_size = strlen(gcfs->metadata); 301 | for (i = 4; i < 6; i++) 302 | gcfs->metadata[gcfs->metadata_size++] = 303 | isprint(workspace[i]) ? workspace[i] : '?'; 304 | strcat(gcfs->metadata, " ("); 305 | strcat(gcfs->metadata, gamecube_publisher_name(workspace[4], workspace[5])); 306 | strcat(gcfs->metadata, ")"); 307 | strncat(gcfs->metadata, CRLF, strlen(CRLF)); 308 | strcat(gcfs->metadata, "Title: "); 309 | strncat(gcfs->metadata, &workspace[32], 0x3E0); 310 | strncat(gcfs->metadata, CRLF, strlen(CRLF)); 311 | 312 | gcfs->metadata[METADATA_FILE_MAX_SIZE - 1] = 0; 313 | gcfs->metadata_size = strlen(gcfs->metadata); 314 | 315 | tree_insert(gcfs->tree, METADATA_FILE_NAME, sizeof(METADATA_FILE_NAME), 316 | 0, gcfs->metadata_size); 317 | 318 | // decide on a filename for the main executable-- lowercase 319 | // all characters; replace spaces with dashes; discard non-alphanumeric 320 | // characters 321 | j = 0; 322 | for (i = 0; i < 0x3E0; i++) { 323 | c = workspace[32 + i]; 324 | if (c == ' ') 325 | main_dol_filename[j++] = '-'; 326 | else if (isalnum(c)) { 327 | if (isupper(c)) 328 | main_dol_filename[j++] = tolower(c); 329 | else 330 | main_dol_filename[j++] = c; 331 | } 332 | } 333 | main_dol_filename[j] = 0; 334 | strcat(main_dol_filename, "-exe.dol"); 335 | 336 | // find the main executable file-- this involves seeking to the location 337 | // of the DOL, reading the first 256 bytes, and deciding which section of 338 | // text or data section extends the farthest 339 | main_dol_offset = BE_32(&workspace[0x420]); 340 | lseek(gcfs->fd, main_dol_offset, SEEK_SET); 341 | if (read(gcfs->fd, dol_header, 256) != 256) { 342 | fprintf(stderr, "no main executable file found\n"); 343 | close(gcfs->fd); 344 | free(gcfs); 345 | fuse_exit(fuse_get_context()->fuse); 346 | return NULL; 347 | } 348 | max_dol_section_offset = 0; 349 | // iterate through the 7 code segments 350 | for (i = 0; i < 7; i++) { 351 | section_offset = BE_32(&dol_header[i * 4]); 352 | section_size = BE_32(&dol_header[0x90 + i * 4]); 353 | if (section_offset + section_size > max_dol_section_offset) 354 | max_dol_section_offset = section_offset + section_size; 355 | } 356 | // iterate through the 10 code segments 357 | for (i = 0; i < 10; i++) { 358 | section_offset = BE_32(&dol_header[0x1C + i * 4]); 359 | section_size = BE_32(&dol_header[0xAC + i * 4]); 360 | if (section_offset + section_size > max_dol_section_offset) 361 | max_dol_section_offset = section_offset + section_size; 362 | } 363 | tree_insert(gcfs->tree, main_dol_filename, strlen(main_dol_filename), 364 | main_dol_offset, max_dol_section_offset); 365 | 366 | // find the filesystem pointer at 0x424 367 | fst_chunk = BE_32(&workspace[0x424]); 368 | lseek(gcfs->fd, fst_chunk, SEEK_SET); 369 | 370 | // read the first file record 371 | if (read(gcfs->fd, workspace, 12) != 12) { 372 | fprintf(stderr, "file too small to be a GCFS file\n"); 373 | close(gcfs->fd); 374 | free(gcfs); 375 | fuse_exit(fuse_get_context()->fuse); 376 | return NULL; 377 | } 378 | file_record_count = BE_32(&workspace[8]); 379 | file_records_size = file_record_count * 12; 380 | file_records = (unsigned char *)malloc(file_records_size); 381 | if (!file_records) { 382 | fprintf(stderr,"not enough memory\n"); 383 | close(gcfs->fd); 384 | fuse_exit(fuse_get_context()->fuse); 385 | return NULL; 386 | } 387 | 388 | // copy the first record over 389 | memcpy(file_records, workspace, 12); 390 | 391 | // load the remaining records 392 | if (read(gcfs->fd, file_records + 12, file_records_size - 12) != 393 | file_records_size - 12) { 394 | fprintf(stderr, "file too small to be a GCFS file\n"); 395 | close(gcfs->fd); 396 | free(gcfs); 397 | fuse_exit(fuse_get_context()->fuse); 398 | return NULL; 399 | } 400 | filename_base_offset = lseek(gcfs->fd, 0, SEEK_CUR); 401 | name_buffer[0] = 0; 402 | 403 | // build the tree 404 | gcfs_recurse_directory(file_records, 2, file_record_count, 405 | name_buffer, 0, gcfs->fd, filename_base_offset, 406 | gcfs->tree); 407 | 408 | return (void *)gcfs; 409 | } 410 | 411 | /*! 412 | * \brief Clean up filesystem. 413 | */ 414 | static void gcfs_destroy(void *context) 415 | { 416 | struct gcfsfile *gcfs = (struct gcfsfile *)context; 417 | 418 | if (gcfs) { 419 | close(gcfs->fd); 420 | tree_free(gcfs->tree); 421 | free(gcfs); 422 | } 423 | } 424 | 425 | /*! 426 | * \brief The FUSE file system operations. 427 | */ 428 | struct fuse_operations gcfs_operations = { 429 | .getattr = gcfs_getattr, 430 | .open = gcfs_open, 431 | .read = gcfs_read, 432 | .opendir = gcfs_opendir, 433 | .readdir = gcfs_readdir, 434 | .init = gcfs_init, 435 | .destroy = gcfs_destroy, 436 | }; 437 | -------------------------------------------------------------------------------- /src/gcfs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 Mike Melanson (mike at multimedia.cx) 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | */ 18 | 19 | /*! 20 | * \file gcfs.h 21 | * \author Mike Melanson 22 | * \brief GCFS file support header file. 23 | */ 24 | 25 | #ifndef _GCFS_H_ 26 | #define _GCFS_H_ 27 | 28 | #define _GNU_SOURCE 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #define METADATA_FILE_MAX_SIZE 2048 42 | 43 | /*! 44 | * \brief Basic information about one GCFS file. 45 | 46 | * This structure contains basic information about one GCFS file, 47 | * including information needed by FUSE system. It is stored as \c 48 | * private_data of FUSE context. 49 | */ 50 | struct gcfsfile { 51 | /*! 52 | * \brief GCFS file descriptor. 53 | */ 54 | int fd; 55 | 56 | /*! 57 | * \brief Disk operations mutex. 58 | * 59 | * This mutex is used to synchronize disk operations on GCFS 60 | * file. Whenever one need to read/write/lseek GCFS file, this 61 | * mutex should be locked with \c pthread_mutex_lock(). After 62 | * operation has finished (also after an error), this mutex 63 | * should be unlocked with \c pthread_mutex_unlock(). 64 | */ 65 | pthread_mutex_t mutex; 66 | 67 | /*! 68 | * \brief Size of the GCFS file. 69 | */ 70 | off_t size; 71 | 72 | /*! 73 | * \brief Directory tree of the GCFS file. 74 | * 75 | * This field contains directory tree of the GCFS file (which 76 | * doesn't constain any directories, only files). This is 77 | * filled by \c gcfs_init(). 78 | */ 79 | struct tree *tree; 80 | 81 | /*! 82 | * \brief GameCube filesystem metadata. 83 | * 84 | * This array acts as a container for metadata about the 85 | * the mounted filesystem (title, publisher, etc.). 86 | */ 87 | char metadata[METADATA_FILE_MAX_SIZE]; 88 | int metadata_size; 89 | }; 90 | 91 | extern struct fuse_operations gcfs_operations; 92 | 93 | extern int gcfs_fd; 94 | 95 | //! Treat given memory address as a 16-bit big-endian integer. 96 | #define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) 97 | 98 | //! Treat given memory address as a 32-bit big-endian integer. 99 | #define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ 100 | (((uint8_t*)(x))[1] << 16) | \ 101 | (((uint8_t*)(x))[2] << 8) | \ 102 | ((uint8_t*)(x))[3]) 103 | 104 | //! Treat given memory address as a 16-bit little-endian integer. 105 | #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) 106 | 107 | //! Treat given memory address as a 32-bit little-endian integer. 108 | #define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \ 109 | (((uint8_t*)(x))[2] << 16) | \ 110 | (((uint8_t*)(x))[1] << 8) | \ 111 | ((uint8_t*)(x))[0]) 112 | 113 | #endif // _GCFS_H_ 114 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 Mike Melanson (mike at multimedia.cx) 3 | * based on code by: 4 | * Copyright (C) 2005 Janusz Dziemidowicz (rraptorr@nails.eu.org) 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | /*! 22 | * \file main.c 23 | * \author Mike Melanson 24 | * \brief Main program function. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | //! FUSE library compliance level. 32 | #define FUSE_USE_VERSION 25 33 | #include 34 | 35 | #include "gcfs.h" 36 | 37 | /*! 38 | * \brief Flag indicating wheter we should run in quiet mode (0 - no, 39 | * all other values - yes). 40 | */ 41 | int quiet; 42 | 43 | /*! 44 | * \brief Main function. 45 | */ 46 | int main(int argc, char *argv[]) 47 | { 48 | char **nargv; 49 | int nargc, i, j; 50 | 51 | if (argc < 3) { 52 | fprintf 53 | (stderr, 54 | "Usage: %s [] []\n\n", 55 | argv[0]); 56 | fprintf(stderr, "Available options:\n"); 57 | fprintf(stderr, 58 | "\t-q - quiet mode (print only error messages)\n"); 59 | exit(EXIT_FAILURE); 60 | } 61 | 62 | for (i = 1; i < argc; i++) { 63 | if (!strcmp(argv[i], "-q")) { 64 | quiet = 1; 65 | for (j = i; j < argc - 1; j++) 66 | argv[j] = argv[j + 1]; 67 | argc--; 68 | break; 69 | } 70 | } 71 | 72 | nargc = argc - 1; 73 | nargv = (char **)malloc(nargc * sizeof(char *)); 74 | 75 | // skip the resource filename 76 | nargv[0] = argv[0]; 77 | for (i = 1; i < nargc; i++) 78 | nargv[i] = argv[i + 1]; 79 | 80 | // try to open the file 81 | gcfs_fd = open(argv[1], O_RDONLY); 82 | if (gcfs_fd < 0) { 83 | perror(argv[1]); 84 | exit(EXIT_FAILURE); 85 | } 86 | 87 | return fuse_main(nargc, nargv, &gcfs_operations); 88 | } 89 | -------------------------------------------------------------------------------- /src/tree.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005 Janusz Dziemidowicz (rraptorr@nails.eu.org) 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | */ 18 | 19 | /*! 20 | * \file tree.c 21 | * \author Janusz Dziemidowicz 22 | * \brief Directory hierarchy abstraction file. 23 | */ 24 | 25 | #include "tree.h" 26 | 27 | void tree_insert(struct tree *root, const char *path, int length, 28 | long offset, long size) 29 | { 30 | char *pos; 31 | struct tree *node; 32 | 33 | if (!path || !*path) 34 | return; 35 | 36 | if ((pos = memchr(path, '/', length))) { 37 | // Path contains directory. 38 | *pos = '\0'; 39 | node = root->sub; 40 | 41 | // Check if this directory was already inserted by earlier calls. 42 | while (node) { 43 | if (!strcmp(node->name, path)) { 44 | tree_insert(node, pos + 1, 45 | length - (pos + 1 - path), 46 | offset, size); 47 | return; 48 | } 49 | node = node->next; 50 | } 51 | 52 | // Create new directory. 53 | node = (struct tree *)malloc(sizeof(struct tree)); 54 | node->name = strdup(path); 55 | node->is_dir = 1; 56 | node->offset = 0; 57 | node->size = 0; 58 | node->nsubdirs = 0; 59 | node->sub = NULL; 60 | node->next = root->sub; 61 | 62 | // Connect new directory under current directory. 63 | root->sub = node; 64 | root->nsubdirs++; 65 | 66 | // Insert remaining parts of path in new directory. 67 | tree_insert(node, pos + 1, length - (pos + 1 - path), 68 | offset, size); 69 | } else { 70 | // No more directories in path. Just create new file 71 | // under current directory. 72 | node = (struct tree *)malloc(sizeof(struct tree)); 73 | node->name = strndup(path, length); 74 | node->is_dir = 0; 75 | node->offset = offset; 76 | node->size = size; 77 | node->nsubdirs = 0; 78 | node->sub = NULL; 79 | node->next = root->sub; 80 | root->sub = node; 81 | } 82 | } 83 | 84 | struct tree *tree_find_entry(struct tree *root, const char *path) 85 | { 86 | struct tree *node, *ret; 87 | const char *next; 88 | 89 | if (!root) 90 | return NULL; 91 | 92 | if (!strcmp(path, root->name)) 93 | return root; 94 | 95 | if (strncmp(path, root->name, strlen(root->name))) 96 | return NULL; 97 | 98 | next = path + strlen(root->name); 99 | if (*next != '/') 100 | return NULL; 101 | next++; 102 | 103 | if (!*next) 104 | return root; 105 | 106 | node = root->sub; 107 | while (node) { 108 | ret = tree_find_entry(node, next); 109 | if (ret) 110 | return ret; 111 | 112 | node = node->next; 113 | } 114 | 115 | return NULL; 116 | } 117 | 118 | void tree_free(struct tree *root) 119 | { 120 | struct tree *node, *next; 121 | 122 | node = root->sub; 123 | while (node) { 124 | next = node->next; 125 | tree_free(node); 126 | node = next; 127 | } 128 | 129 | free(root->name); 130 | free(root); 131 | } 132 | 133 | struct tree *tree_empty(void) 134 | { 135 | struct tree *ret; 136 | 137 | ret = (struct tree *)malloc(sizeof(struct tree)); 138 | ret->name = strdup(""); 139 | ret->is_dir = 1; 140 | ret->offset = 0; 141 | ret->size = 0; 142 | ret->nsubdirs = 0; 143 | ret->sub = NULL; 144 | ret->next = NULL; 145 | 146 | return ret; 147 | } 148 | 149 | int tree_getattr(const char *path, struct stat *stbuf, struct tree *root, 150 | int fd) 151 | { 152 | struct tree *node; 153 | struct stat st; 154 | 155 | node = tree_find_entry(root, path); 156 | if (node) { 157 | memset(stbuf, 0, sizeof(struct stat)); 158 | // Set UID and GID to current user 159 | stbuf->st_uid = getuid(); 160 | stbuf->st_gid = getgid(); 161 | if (node->is_dir) { 162 | stbuf->st_mode = 163 | S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR 164 | | S_IXGRP | S_IXOTH; 165 | // Directory should have number of links set 166 | // to 2 + number of subdirectories (not 167 | // files), this makes find work. 168 | stbuf->st_nlink = 2 + node->nsubdirs; 169 | } else { 170 | stbuf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; 171 | stbuf->st_nlink = 1; 172 | stbuf->st_size = node->size; 173 | } 174 | 175 | // Set all times to the values from PACK file. 176 | fstat(fd, &st); 177 | stbuf->st_atime = st.st_atime; 178 | stbuf->st_mtime = st.st_mtime; 179 | stbuf->st_ctime = st.st_ctime; 180 | return 0; 181 | } else 182 | return -ENOENT; 183 | } 184 | 185 | int tree_open(const char *path, struct fuse_file_info *fi, struct tree *root) 186 | { 187 | struct tree *node; 188 | 189 | if (fi->flags & O_WRONLY) 190 | return -EROFS; 191 | 192 | node = tree_find_entry(root, path); 193 | 194 | if (!node) 195 | return -ENOENT; 196 | 197 | return 0; 198 | } 199 | 200 | int tree_read(const char *path, char *buf, size_t size, 201 | off_t offset, struct fuse_file_info *fi, struct tree *root, 202 | int fd, pthread_mutex_t * mutex) 203 | { 204 | struct tree *node; 205 | int ret; 206 | 207 | node = tree_find_entry(root, path); 208 | if (!node) 209 | return -ENOENT; 210 | 211 | if (node->is_dir) 212 | return -EISDIR; 213 | 214 | if (offset >= node->size) 215 | return 0; 216 | if (offset + size > node->size) 217 | size = node->size - offset; 218 | 219 | // This is needed to ensure, that no other thread will change 220 | // seek point before we call read(). 221 | pthread_mutex_lock(mutex); 222 | 223 | lseek(fd, node->offset + offset, SEEK_SET); 224 | ret = read(fd, buf, size); 225 | 226 | pthread_mutex_unlock(mutex); 227 | 228 | return ret; 229 | } 230 | 231 | int tree_opendir(const char *path, struct fuse_file_info *fi, struct tree *root) 232 | { 233 | struct tree *node = tree_find_entry(root, path); 234 | 235 | if (!node) 236 | return -ENOENT; 237 | 238 | if (!node->is_dir) 239 | return -ENOTDIR; 240 | 241 | return 0; 242 | } 243 | 244 | int tree_readdir(const char *path, void *buf, 245 | fuse_fill_dir_t filler, off_t offset, 246 | struct fuse_file_info *fi, struct tree *root) 247 | { 248 | struct tree *node; 249 | 250 | node = tree_find_entry(root, path); 251 | 252 | if (!node) 253 | return -ENOENT; 254 | 255 | if (!node->is_dir) 256 | return -ENOTDIR; 257 | 258 | filler(buf, ".", NULL, 0); 259 | filler(buf, "..", NULL, 0); 260 | 261 | node = node->sub; 262 | while (node) { 263 | filler(buf, node->name, NULL, 0); 264 | node = node->next; 265 | } 266 | 267 | return 0; 268 | } 269 | -------------------------------------------------------------------------------- /src/tree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005 Janusz Dziemidowicz (rraptorr@nails.eu.org) 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | */ 18 | 19 | /*! 20 | * \file tree.h 21 | * \author Janusz Dziemidowicz 22 | * \brief Directory hierarchy abstraction header file. 23 | */ 24 | 25 | #ifndef _TREE_H_ 26 | #define _TREE_H_ 27 | 28 | //! This is needed for strndup. 29 | #define _GNU_SOURCE 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | //! FUSE library compliance level. 41 | #define FUSE_USE_VERSION 25 42 | #include 43 | 44 | /*! 45 | * \brief GRAF directory hierarchy structure. 46 | * 47 | * This structure represents directory structure from GRAF. You should 48 | * insert files into this structure (filenames can contain '/', 49 | * corresponding directories will be made automatically). There are 50 | * also FUSE operations on this structure provided, which can be used 51 | * to quickly implement FUSE filesystem. 52 | */ 53 | struct tree { 54 | /*! 55 | * \brief Filename. 56 | * 57 | * Should be empty string in the root of the tree. Otherwise 58 | * searching function won't work. 59 | */ 60 | char *name; 61 | 62 | /*! 63 | * \brief Flag indicating that this a directory. 64 | */ 65 | char is_dir; 66 | 67 | /*! 68 | * \brief Offset of the file inside of GRAF. 69 | */ 70 | off_t offset; 71 | 72 | /*! 73 | * \brief Size of the file inside of GRAF. 74 | */ 75 | off_t size; 76 | 77 | /*! 78 | * \brief Number of subdirectories. 79 | * 80 | * This is used to calculate correct number of hard links, 81 | * which for directories should be 2 + number of 82 | * subdirectories. This is especially needed to make find 83 | * work. It will be incremented when inserting directories. 84 | */ 85 | int nsubdirs; 86 | 87 | /*! 88 | * \brief Subdirectories. 89 | * 90 | * If the current file is a regular file this field is NULL. Otherwise 91 | * it is a pointer to first element of directory. 92 | */ 93 | struct tree *sub; 94 | 95 | /*! 96 | * \brief Next file. 97 | * 98 | * This is a pointer to the next file on the same directory 99 | * level. 100 | */ 101 | struct tree *next; 102 | }; 103 | 104 | /*! 105 | * \brief Insert path into representation of GRAF firectory tree. 106 | * 107 | * This function inserts given pathname into the \c tree structure, 108 | * which describes directory structure inside of GRAF. Every needed 109 | * subdirectories will be created by this function. 110 | * 111 | * \param root \c tree root, at which \c path should be inserted. 112 | * \param path path that should be inserted. This should be relative 113 | * name (no '/' in the beginning). Please note that it will be 114 | * destroyed. 115 | * \param length length of \c path (as sometimes it is not zero 116 | * terminated). 117 | * \param offset offset (from \c packentry) that should be stored in 118 | * the tree node corresponding to given \c path. 119 | * \param size size (from \c packentry) that should be stored in the 120 | * tree node correspoding to given \c path. 121 | */ 122 | void tree_insert(struct tree *root, const char *path, int length, 123 | long offset, long size); 124 | 125 | /*! 126 | * \brief Find given path in GRAF directory structure. 127 | * 128 | * \param root \c tree root, at which searching should be started. 129 | * \param path path to find, it should be exactly as provided by FUSE 130 | * (so it should start with '/'). 131 | * \return pointer to node containing information about given \c path 132 | * or NULL if not found. 133 | */ 134 | struct tree *tree_find_entry(struct tree *root, const char *path); 135 | 136 | /*! 137 | * \brief Free entire GRAF directory hierarchy structure. 138 | * 139 | * \param root root of the directory \c tree to be freed. 140 | */ 141 | void tree_free(struct tree *root); 142 | 143 | /*! 144 | * \brief Create empty directory structure. 145 | * 146 | * This functions creates empty directory structures with all fields 147 | * set as needed. 148 | */ 149 | struct tree *tree_empty(void); 150 | 151 | /*! 152 | * \brief FUSE getattr operation. 153 | * 154 | * This is FUSE compatible getattr operation which gets file 155 | * information from \c tree structure. 156 | * \param path file path. 157 | * \param stbuf stats will be stored here. 158 | * \param root tree root. 159 | * \param fd data file descriptor. 160 | * \return 0 on success, -errno otherwise. 161 | */ 162 | int tree_getattr(const char *path, struct stat *stbuf, struct tree *root, 163 | int fd); 164 | 165 | /*! 166 | * \brief FUSE open operation. 167 | * 168 | * This is FUSE compatible open operation which gets file 169 | * information from \c tree structure. 170 | * \param path file path. 171 | * \param fi FUSE file information. 172 | * \param root tree root. 173 | * \return 0 on success, -errno otherwise. 174 | */ 175 | int tree_open(const char *path, struct fuse_file_info *fi, struct tree *root); 176 | 177 | /*! 178 | * \brief FUSE read operation. 179 | * 180 | * This is FUSE compatible read operation which gets file 181 | * information from \c tree structure. 182 | * \param path file path. 183 | * \param buf read buffer. 184 | * \param size size of \c buf. 185 | * \param offset read offset. 186 | * \param fi FUSE file information. 187 | * \param root tree root. 188 | * \param fd data file descriptor. 189 | * \param mutex file operations mutex related to \c fd. 190 | * \return number of bytes read on success, -errno otherwise. 191 | */ 192 | int tree_read(const char *path, char *buf, size_t size, 193 | off_t offset, struct fuse_file_info *fi, struct tree *root, 194 | int fd, pthread_mutex_t * mutex); 195 | 196 | /*! 197 | * \brief FUSE opendir operation. 198 | * 199 | * This is FUSE compatible opendir operation which gets file 200 | * information from \c tree structure. 201 | * \param path directory path. 202 | * \param fi FUSE file information. 203 | * \param root tree root. 204 | * \return 0 on success, -errno otherwise. 205 | */ 206 | int tree_opendir(const char *path, struct fuse_file_info *fi, 207 | struct tree *root); 208 | 209 | /*! 210 | * \brief FUSE readdir operation. 211 | * 212 | * This is FUSE compatible readdir operation which gets file 213 | * information from \c tree structure. 214 | * \param path directory path. 215 | * \param buf output buffer. 216 | * \param filler filler function. 217 | * \param offset output offset. 218 | * \param fi FUSE file information. 219 | * \param root tree root. 220 | * \return 0 on success, -errno otherwise. 221 | */ 222 | int tree_readdir(const char *path, void *buf, 223 | fuse_fill_dir_t filler, off_t offset, 224 | struct fuse_file_info *fi, struct tree *root); 225 | 226 | #endif // _TREE_H_ 227 | --------------------------------------------------------------------------------