Initial commit
This commit is contained in:
commit
d30e71d923
|
|
@ -0,0 +1,34 @@
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP shares
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
# Xcode
|
||||||
|
xcuserdata/
|
||||||
|
*.xcodeproj/*
|
||||||
|
!*.xcodeproj/project.pbxproj
|
||||||
|
!*.xcodeproj/xcshareddata/
|
||||||
|
!*.xcworkspace/contents.xcworkspacedata
|
||||||
|
**/xcshareddata/WorkspaceSettings.xcsettings
|
||||||
|
|
||||||
|
|
@ -0,0 +1,339 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
||||||
|
|
@ -0,0 +1,308 @@
|
||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 46;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
436C6B011C59595E00C4FE10 /* loopback.c in Sources */ = {isa = PBXBuildFile; fileRef = 436C6B001C59595E00C4FE10 /* loopback.c */; };
|
||||||
|
43E954082649F92C009CCB55 /* libfuse.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 43E954072649F92C009CCB55 /* libfuse.2.dylib */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
436C6AFD1C59595E00C4FE10 /* loopback */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = loopback; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
436C6B001C59595E00C4FE10 /* loopback.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loopback.c; sourceTree = "<group>"; };
|
||||||
|
43ADB58922817D2200B49726 /* loopback.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = loopback.entitlements; sourceTree = "<group>"; };
|
||||||
|
43E953B12646EC9A009CCB55 /* LICENSE.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE.txt; sourceTree = "<group>"; };
|
||||||
|
43E954072649F92C009CCB55 /* libfuse.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libfuse.2.dylib; path = ../../../../../../../usr/local/lib/libfuse.2.dylib; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
436C6AFA1C59595E00C4FE10 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
43E954082649F92C009CCB55 /* libfuse.2.dylib in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
436C6AF41C59595E00C4FE10 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
43E953B12646EC9A009CCB55 /* LICENSE.txt */,
|
||||||
|
436C6AFF1C59595E00C4FE10 /* loopback */,
|
||||||
|
43E954062649F92C009CCB55 /* Frameworks */,
|
||||||
|
436C6AFE1C59595E00C4FE10 /* Products */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
436C6AFE1C59595E00C4FE10 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
436C6AFD1C59595E00C4FE10 /* loopback */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
436C6AFF1C59595E00C4FE10 /* loopback */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
43ADB58922817D2200B49726 /* loopback.entitlements */,
|
||||||
|
436C6B001C59595E00C4FE10 /* loopback.c */,
|
||||||
|
);
|
||||||
|
path = loopback;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
43E954062649F92C009CCB55 /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
43E954072649F92C009CCB55 /* libfuse.2.dylib */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
436C6AFC1C59595E00C4FE10 /* loopback */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 436C6B041C59595E00C4FE10 /* Build configuration list for PBXNativeTarget "loopback" */;
|
||||||
|
buildPhases = (
|
||||||
|
436C6AF91C59595E00C4FE10 /* Sources */,
|
||||||
|
436C6AFA1C59595E00C4FE10 /* Frameworks */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = loopback;
|
||||||
|
productName = loopback;
|
||||||
|
productReference = 436C6AFD1C59595E00C4FE10 /* loopback */;
|
||||||
|
productType = "com.apple.product-type.tool";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
436C6AF51C59595E00C4FE10 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
LastUpgradeCheck = 1240;
|
||||||
|
ORGANIZATIONNAME = "Benjamin Fleischer";
|
||||||
|
TargetAttributes = {
|
||||||
|
436C6AFC1C59595E00C4FE10 = {
|
||||||
|
CreatedOnToolsVersion = 7.2;
|
||||||
|
ProvisioningStyle = Manual;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 436C6AF81C59595E00C4FE10 /* Build configuration list for PBXProject "loopback" */;
|
||||||
|
compatibilityVersion = "Xcode 3.2";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 436C6AF41C59595E00C4FE10;
|
||||||
|
productRefGroup = 436C6AFE1C59595E00C4FE10 /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
436C6AFC1C59595E00C4FE10 /* loopback */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
436C6AF91C59595E00C4FE10 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
436C6B011C59595E00C4FE10 /* loopback.c in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
436C6B021C59595E00C4FE10 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
436C6B031C59595E00C4FE10 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
436C6B051C59595E00C4FE10 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_ENTITLEMENTS = loopback/loopback.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"_FILE_OFFSET_BITS=64",
|
||||||
|
_DARWIN_USE_64_BIT_INODE,
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
|
||||||
|
HEADER_SEARCH_PATHS = "\"/usr/local/include\"";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "@executable_path/";
|
||||||
|
LIBRARY_SEARCH_PATHS = "\"/usr/local/lib\"";
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
|
OTHER_CODE_SIGN_FLAGS = "--timestamp";
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "io.macfuse.demo.loopbackfs-c";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
436C6B061C59595E00C4FE10 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_ENTITLEMENTS = loopback/loopback.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"_FILE_OFFSET_BITS=64",
|
||||||
|
_DARWIN_USE_64_BIT_INODE,
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
|
||||||
|
HEADER_SEARCH_PATHS = "\"/usr/local/include\"";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "@executable_path/";
|
||||||
|
LIBRARY_SEARCH_PATHS = "\"/usr/local/lib\"";
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
|
OTHER_CODE_SIGN_FLAGS = "--timestamp";
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "io.macfuse.demo.loopbackfs-c";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
436C6AF81C59595E00C4FE10 /* Build configuration list for PBXProject "loopback" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
436C6B021C59595E00C4FE10 /* Debug */,
|
||||||
|
436C6B031C59595E00C4FE10 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
436C6B041C59595E00C4FE10 /* Build configuration list for PBXNativeTarget "loopback" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
436C6B051C59595E00C4FE10 /* Debug */,
|
||||||
|
436C6B061C59595E00C4FE10 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 436C6AF51C59595E00C4FE10 /* Project object */;
|
||||||
|
}
|
||||||
7
LoopbackFS-C/loopback.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
LoopbackFS-C/loopback.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:loopback.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1240"
|
||||||
|
version = "1.7">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "436C6AFC1C59595E00C4FE10"
|
||||||
|
BuildableName = "loopback"
|
||||||
|
BlueprintName = "loopback"
|
||||||
|
ReferencedContainer = "container:loopback.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "436C6AFC1C59595E00C4FE10"
|
||||||
|
BuildableName = "loopback"
|
||||||
|
BlueprintName = "loopback"
|
||||||
|
ReferencedContainer = "container:loopback.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<PreActions>
|
||||||
|
<ExecutionAction
|
||||||
|
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
|
||||||
|
<ActionContent
|
||||||
|
title = "Run Script"
|
||||||
|
scriptText = "# Unmount volumes umount -A -t "${OSXFUSE_NAME}" # Create source directory and mount point mkdir -p /tmp/dir mkdir -p /Volumes/loop">
|
||||||
|
<EnvironmentBuildable>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "436C6AFC1C59595E00C4FE10"
|
||||||
|
BuildableName = "loopback"
|
||||||
|
BlueprintName = "loopback"
|
||||||
|
ReferencedContainer = "container:loopback.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</EnvironmentBuildable>
|
||||||
|
</ActionContent>
|
||||||
|
</ExecutionAction>
|
||||||
|
</PreActions>
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "436C6AFC1C59595E00C4FE10"
|
||||||
|
BuildableName = "loopback"
|
||||||
|
BlueprintName = "loopback"
|
||||||
|
ReferencedContainer = "container:loopback.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
<CommandLineArguments>
|
||||||
|
<CommandLineArgument
|
||||||
|
argument = "-omodules=threadid:subdir,subdir=/tmp/dir"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</CommandLineArgument>
|
||||||
|
<CommandLineArgument
|
||||||
|
argument = "-oallow_other,native_xattr,volname=loopback"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</CommandLineArgument>
|
||||||
|
<CommandLineArgument
|
||||||
|
argument = "-f"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</CommandLineArgument>
|
||||||
|
<CommandLineArgument
|
||||||
|
argument = "/Volumes/loop"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</CommandLineArgument>
|
||||||
|
</CommandLineArguments>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "436C6AFC1C59595E00C4FE10"
|
||||||
|
BuildableName = "loopback"
|
||||||
|
BlueprintName = "loopback"
|
||||||
|
ReferencedContainer = "container:loopback.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
|
|
@ -0,0 +1,980 @@
|
||||||
|
/*
|
||||||
|
FUSE: Filesystem in Userspace
|
||||||
|
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||||
|
|
||||||
|
This program can be distributed under the terms of the GNU GPL.
|
||||||
|
See the file LICENSE.txt.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loopback macFUSE file system in C. Uses the high-level FUSE API.
|
||||||
|
* Based on the fusexmp_fh.c example from the Linux FUSE distribution.
|
||||||
|
* Amit Singh <http://osxbook.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AvailabilityMacros.h>
|
||||||
|
|
||||||
|
#define HAVE_EXCHANGE 0
|
||||||
|
#define HAVE_RENAMEX 1
|
||||||
|
|
||||||
|
#define FUSE_USE_VERSION 26
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <fuse.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/xattr.h>
|
||||||
|
#include <sys/attr.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/vnode.h>
|
||||||
|
|
||||||
|
#if defined(_POSIX_C_SOURCE)
|
||||||
|
typedef unsigned char u_char;
|
||||||
|
typedef unsigned short u_short;
|
||||||
|
typedef unsigned int u_int;
|
||||||
|
typedef unsigned long u_long;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define G_PREFIX "org"
|
||||||
|
#define G_KAUTH_FILESEC_XATTR G_PREFIX ".apple.system.Security"
|
||||||
|
#define A_PREFIX "com"
|
||||||
|
#define A_KAUTH_FILESEC_XATTR A_PREFIX ".apple.system.Security"
|
||||||
|
#define XATTR_APPLE_PREFIX "com.apple."
|
||||||
|
|
||||||
|
struct loopback {
|
||||||
|
int case_insensitive;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct loopback loopback;
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_getattr(const char *path, struct stat *stbuf)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = lstat(path, stbuf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The optimal I/O size can be set on a per-file basis. Setting st_blksize
|
||||||
|
* to zero will cause the kernel extension to fall back on the global I/O
|
||||||
|
* size which can be specified at mount-time (option iosize).
|
||||||
|
*/
|
||||||
|
stbuf->st_blksize = 0;
|
||||||
|
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_fgetattr(const char *path, struct stat *stbuf,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
(void)path;
|
||||||
|
|
||||||
|
res = fstat(fi->fh, stbuf);
|
||||||
|
|
||||||
|
// Fall back to global I/O size. See loopback_getattr().
|
||||||
|
stbuf->st_blksize = 0;
|
||||||
|
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_readlink(const char *path, char *buf, size_t size)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = readlink(path, buf, size - 1);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[res] = '\0';
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct loopback_dirp {
|
||||||
|
DIR *dp;
|
||||||
|
struct dirent *entry;
|
||||||
|
off_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_opendir(const char *path, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
struct loopback_dirp *d = malloc(sizeof(struct loopback_dirp));
|
||||||
|
if (d == NULL) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->dp = opendir(path);
|
||||||
|
if (d->dp == NULL) {
|
||||||
|
res = -errno;
|
||||||
|
free(d);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->offset = 0;
|
||||||
|
d->entry = NULL;
|
||||||
|
|
||||||
|
fi->fh = (unsigned long)d;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct loopback_dirp *
|
||||||
|
get_dirp(struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
return (struct loopback_dirp *)(uintptr_t)fi->fh;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||||
|
off_t offset, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
struct loopback_dirp *d = get_dirp(fi);
|
||||||
|
|
||||||
|
(void)path;
|
||||||
|
|
||||||
|
if (offset == 0) {
|
||||||
|
rewinddir(d->dp);
|
||||||
|
d->entry = NULL;
|
||||||
|
d->offset = 0;
|
||||||
|
} else if (offset != d->offset) {
|
||||||
|
seekdir(d->dp, offset);
|
||||||
|
d->entry = NULL;
|
||||||
|
d->offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
struct stat st;
|
||||||
|
off_t nextoff;
|
||||||
|
|
||||||
|
if (!d->entry) {
|
||||||
|
d->entry = readdir(d->dp);
|
||||||
|
if (!d->entry) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&st, 0, sizeof(st));
|
||||||
|
st.st_ino = d->entry->d_ino;
|
||||||
|
st.st_mode = d->entry->d_type << 12;
|
||||||
|
nextoff = telldir(d->dp);
|
||||||
|
if (filler(buf, d->entry->d_name, &st, nextoff)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->entry = NULL;
|
||||||
|
d->offset = nextoff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_releasedir(const char *path, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
struct loopback_dirp *d = get_dirp(fi);
|
||||||
|
|
||||||
|
(void)path;
|
||||||
|
|
||||||
|
closedir(d->dp);
|
||||||
|
free(d);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_mknod(const char *path, mode_t mode, dev_t rdev)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (S_ISFIFO(mode)) {
|
||||||
|
res = mkfifo(path, mode);
|
||||||
|
} else {
|
||||||
|
res = mknod(path, mode, rdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_mkdir(const char *path, mode_t mode)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = mkdir(path, mode);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_unlink(const char *path)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = unlink(path);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_rmdir(const char *path)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = rmdir(path);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_symlink(const char *from, const char *to)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = symlink(from, to);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_rename(const char *from, const char *to)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = rename(from, to);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_EXCHANGE
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_exchange(const char *path1, const char *path2, unsigned long options)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = exchangedata(path1, path2, options);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_EXCHANGE */
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_link(const char *from, const char *to)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = link(from, to);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_fsetattr_x(const char *path, struct setattr_x *attr,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
uid_t uid = -1;
|
||||||
|
gid_t gid = -1;
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_MODE(attr)) {
|
||||||
|
res = fchmod(fi->fh, attr->mode);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_UID(attr)) {
|
||||||
|
uid = attr->uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_GID(attr)) {
|
||||||
|
gid = attr->gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((uid != -1) || (gid != -1)) {
|
||||||
|
res = fchown(fi->fh, uid, gid);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_SIZE(attr)) {
|
||||||
|
res = ftruncate(fi->fh, attr->size);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_MODTIME(attr)) {
|
||||||
|
struct timeval tv[2];
|
||||||
|
if (!SETATTR_WANTS_ACCTIME(attr)) {
|
||||||
|
gettimeofday(&tv[0], NULL);
|
||||||
|
} else {
|
||||||
|
tv[0].tv_sec = attr->acctime.tv_sec;
|
||||||
|
tv[0].tv_usec = attr->acctime.tv_nsec / 1000;
|
||||||
|
}
|
||||||
|
tv[1].tv_sec = attr->modtime.tv_sec;
|
||||||
|
tv[1].tv_usec = attr->modtime.tv_nsec / 1000;
|
||||||
|
res = futimes(fi->fh, tv);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_CRTIME(attr)) {
|
||||||
|
struct attrlist attributes;
|
||||||
|
|
||||||
|
attributes.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||||
|
attributes.reserved = 0;
|
||||||
|
attributes.commonattr = ATTR_CMN_CRTIME;
|
||||||
|
attributes.dirattr = 0;
|
||||||
|
attributes.fileattr = 0;
|
||||||
|
attributes.forkattr = 0;
|
||||||
|
attributes.volattr = 0;
|
||||||
|
|
||||||
|
res = fsetattrlist(fi->fh, &attributes, &attr->crtime,
|
||||||
|
sizeof(struct timespec), FSOPT_NOFOLLOW);
|
||||||
|
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_CHGTIME(attr)) {
|
||||||
|
struct attrlist attributes;
|
||||||
|
|
||||||
|
attributes.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||||
|
attributes.reserved = 0;
|
||||||
|
attributes.commonattr = ATTR_CMN_CHGTIME;
|
||||||
|
attributes.dirattr = 0;
|
||||||
|
attributes.fileattr = 0;
|
||||||
|
attributes.forkattr = 0;
|
||||||
|
attributes.volattr = 0;
|
||||||
|
|
||||||
|
res = fsetattrlist(fi->fh, &attributes, &attr->chgtime,
|
||||||
|
sizeof(struct timespec), FSOPT_NOFOLLOW);
|
||||||
|
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_BKUPTIME(attr)) {
|
||||||
|
struct attrlist attributes;
|
||||||
|
|
||||||
|
attributes.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||||
|
attributes.reserved = 0;
|
||||||
|
attributes.commonattr = ATTR_CMN_BKUPTIME;
|
||||||
|
attributes.dirattr = 0;
|
||||||
|
attributes.fileattr = 0;
|
||||||
|
attributes.forkattr = 0;
|
||||||
|
attributes.volattr = 0;
|
||||||
|
|
||||||
|
res = fsetattrlist(fi->fh, &attributes, &attr->bkuptime,
|
||||||
|
sizeof(struct timespec), FSOPT_NOFOLLOW);
|
||||||
|
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_FLAGS(attr)) {
|
||||||
|
res = fchflags(fi->fh, attr->flags);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_setattr_x(const char *path, struct setattr_x *attr)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
uid_t uid = -1;
|
||||||
|
gid_t gid = -1;
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_MODE(attr)) {
|
||||||
|
res = lchmod(path, attr->mode);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_UID(attr)) {
|
||||||
|
uid = attr->uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_GID(attr)) {
|
||||||
|
gid = attr->gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((uid != -1) || (gid != -1)) {
|
||||||
|
res = lchown(path, uid, gid);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_SIZE(attr)) {
|
||||||
|
res = truncate(path, attr->size);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_MODTIME(attr)) {
|
||||||
|
struct timeval tv[2];
|
||||||
|
if (!SETATTR_WANTS_ACCTIME(attr)) {
|
||||||
|
gettimeofday(&tv[0], NULL);
|
||||||
|
} else {
|
||||||
|
tv[0].tv_sec = attr->acctime.tv_sec;
|
||||||
|
tv[0].tv_usec = attr->acctime.tv_nsec / 1000;
|
||||||
|
}
|
||||||
|
tv[1].tv_sec = attr->modtime.tv_sec;
|
||||||
|
tv[1].tv_usec = attr->modtime.tv_nsec / 1000;
|
||||||
|
res = lutimes(path, tv);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_CRTIME(attr)) {
|
||||||
|
struct attrlist attributes;
|
||||||
|
|
||||||
|
attributes.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||||
|
attributes.reserved = 0;
|
||||||
|
attributes.commonattr = ATTR_CMN_CRTIME;
|
||||||
|
attributes.dirattr = 0;
|
||||||
|
attributes.fileattr = 0;
|
||||||
|
attributes.forkattr = 0;
|
||||||
|
attributes.volattr = 0;
|
||||||
|
|
||||||
|
res = setattrlist(path, &attributes, &attr->crtime,
|
||||||
|
sizeof(struct timespec), FSOPT_NOFOLLOW);
|
||||||
|
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_CHGTIME(attr)) {
|
||||||
|
struct attrlist attributes;
|
||||||
|
|
||||||
|
attributes.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||||
|
attributes.reserved = 0;
|
||||||
|
attributes.commonattr = ATTR_CMN_CHGTIME;
|
||||||
|
attributes.dirattr = 0;
|
||||||
|
attributes.fileattr = 0;
|
||||||
|
attributes.forkattr = 0;
|
||||||
|
attributes.volattr = 0;
|
||||||
|
|
||||||
|
res = setattrlist(path, &attributes, &attr->chgtime,
|
||||||
|
sizeof(struct timespec), FSOPT_NOFOLLOW);
|
||||||
|
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_BKUPTIME(attr)) {
|
||||||
|
struct attrlist attributes;
|
||||||
|
|
||||||
|
attributes.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||||
|
attributes.reserved = 0;
|
||||||
|
attributes.commonattr = ATTR_CMN_BKUPTIME;
|
||||||
|
attributes.dirattr = 0;
|
||||||
|
attributes.fileattr = 0;
|
||||||
|
attributes.forkattr = 0;
|
||||||
|
attributes.volattr = 0;
|
||||||
|
|
||||||
|
res = setattrlist(path, &attributes, &attr->bkuptime,
|
||||||
|
sizeof(struct timespec), FSOPT_NOFOLLOW);
|
||||||
|
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SETATTR_WANTS_FLAGS(attr)) {
|
||||||
|
res = lchflags(path, attr->flags);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_getxtimes(const char *path, struct timespec *bkuptime,
|
||||||
|
struct timespec *crtime)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
struct attrlist attributes;
|
||||||
|
|
||||||
|
attributes.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||||
|
attributes.reserved = 0;
|
||||||
|
attributes.commonattr = 0;
|
||||||
|
attributes.dirattr = 0;
|
||||||
|
attributes.fileattr = 0;
|
||||||
|
attributes.forkattr = 0;
|
||||||
|
attributes.volattr = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct xtimeattrbuf {
|
||||||
|
uint32_t size;
|
||||||
|
struct timespec xtime;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
|
struct xtimeattrbuf buf;
|
||||||
|
|
||||||
|
attributes.commonattr = ATTR_CMN_BKUPTIME;
|
||||||
|
res = getattrlist(path, &attributes, &buf, sizeof(buf), FSOPT_NOFOLLOW);
|
||||||
|
if (res == 0) {
|
||||||
|
(void)memcpy(bkuptime, &(buf.xtime), sizeof(struct timespec));
|
||||||
|
} else {
|
||||||
|
(void)memset(bkuptime, 0, sizeof(struct timespec));
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes.commonattr = ATTR_CMN_CRTIME;
|
||||||
|
res = getattrlist(path, &attributes, &buf, sizeof(buf), FSOPT_NOFOLLOW);
|
||||||
|
if (res == 0) {
|
||||||
|
(void)memcpy(crtime, &(buf.xtime), sizeof(struct timespec));
|
||||||
|
} else {
|
||||||
|
(void)memset(crtime, 0, sizeof(struct timespec));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_create(const char *path, mode_t mode, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open(path, fi->flags, mode);
|
||||||
|
if (fd == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
fi->fh = fd;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_open(const char *path, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open(path, fi->flags);
|
||||||
|
if (fd == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
fi->fh = fd;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_read(const char *path, char *buf, size_t size, off_t offset,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
(void)path;
|
||||||
|
res = pread(fi->fh, buf, size, offset);
|
||||||
|
if (res == -1) {
|
||||||
|
res = -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_write(const char *path, const char *buf, size_t size,
|
||||||
|
off_t offset, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
(void)path;
|
||||||
|
|
||||||
|
res = pwrite(fi->fh, buf, size, offset);
|
||||||
|
if (res == -1) {
|
||||||
|
res = -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_statfs(const char *path, struct statvfs *stbuf)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = statvfs(path, stbuf);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_flush(const char *path, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
(void)path;
|
||||||
|
|
||||||
|
res = close(dup(fi->fh));
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_release(const char *path, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
(void)path;
|
||||||
|
|
||||||
|
close(fi->fh);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_fsync(const char *path, int isdatasync, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
(void)path;
|
||||||
|
|
||||||
|
(void)isdatasync;
|
||||||
|
|
||||||
|
res = fsync(fi->fh);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_setxattr(const char *path, const char *name, const char *value,
|
||||||
|
size_t size, int flags, uint32_t position)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (!strncmp(name, XATTR_APPLE_PREFIX, sizeof(XATTR_APPLE_PREFIX) - 1)) {
|
||||||
|
flags &= ~(XATTR_NOSECURITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(name, A_KAUTH_FILESEC_XATTR)) {
|
||||||
|
|
||||||
|
char new_name[MAXPATHLEN];
|
||||||
|
|
||||||
|
memcpy(new_name, A_KAUTH_FILESEC_XATTR, sizeof(A_KAUTH_FILESEC_XATTR));
|
||||||
|
memcpy(new_name, G_PREFIX, sizeof(G_PREFIX) - 1);
|
||||||
|
|
||||||
|
res = setxattr(path, new_name, value, size, position, XATTR_NOFOLLOW);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
res = setxattr(path, name, value, size, position, XATTR_NOFOLLOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_getxattr(const char *path, const char *name, char *value, size_t size,
|
||||||
|
uint32_t position)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (strcmp(name, A_KAUTH_FILESEC_XATTR) == 0) {
|
||||||
|
|
||||||
|
char new_name[MAXPATHLEN];
|
||||||
|
|
||||||
|
memcpy(new_name, A_KAUTH_FILESEC_XATTR, sizeof(A_KAUTH_FILESEC_XATTR));
|
||||||
|
memcpy(new_name, G_PREFIX, sizeof(G_PREFIX) - 1);
|
||||||
|
|
||||||
|
res = getxattr(path, new_name, value, size, position, XATTR_NOFOLLOW);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
res = getxattr(path, name, value, size, position, XATTR_NOFOLLOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_listxattr(const char *path, char *list, size_t size)
|
||||||
|
{
|
||||||
|
ssize_t res = listxattr(path, list, size, XATTR_NOFOLLOW);
|
||||||
|
if (res > 0) {
|
||||||
|
if (list) {
|
||||||
|
size_t len = 0;
|
||||||
|
char *curr = list;
|
||||||
|
do {
|
||||||
|
size_t thislen = strlen(curr) + 1;
|
||||||
|
if (strcmp(curr, G_KAUTH_FILESEC_XATTR) == 0) {
|
||||||
|
memmove(curr, curr + thislen, res - len - thislen);
|
||||||
|
res -= thislen;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
curr += thislen;
|
||||||
|
len += thislen;
|
||||||
|
} while (len < res);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
ssize_t res2 = getxattr(path, G_KAUTH_FILESEC_XATTR, NULL, 0, 0,
|
||||||
|
XATTR_NOFOLLOW);
|
||||||
|
if (res2 >= 0) {
|
||||||
|
res -= sizeof(G_KAUTH_FILESEC_XATTR);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_removexattr(const char *path, const char *name)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (strcmp(name, A_KAUTH_FILESEC_XATTR) == 0) {
|
||||||
|
|
||||||
|
char new_name[MAXPATHLEN];
|
||||||
|
|
||||||
|
memcpy(new_name, A_KAUTH_FILESEC_XATTR, sizeof(A_KAUTH_FILESEC_XATTR));
|
||||||
|
memcpy(new_name, G_PREFIX, sizeof(G_PREFIX) - 1);
|
||||||
|
|
||||||
|
res = removexattr(path, new_name, XATTR_NOFOLLOW);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
res = removexattr(path, name, XATTR_NOFOLLOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_fallocate(const char *path, int mode, off_t offset, off_t length,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
fstore_t fstore;
|
||||||
|
|
||||||
|
if (!(mode & PREALLOCATE)) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
fstore.fst_flags = 0;
|
||||||
|
if (mode & ALLOCATECONTIG) {
|
||||||
|
fstore.fst_flags |= F_ALLOCATECONTIG;
|
||||||
|
}
|
||||||
|
if (mode & ALLOCATEALL) {
|
||||||
|
fstore.fst_flags |= F_ALLOCATEALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode & ALLOCATEFROMPEOF) {
|
||||||
|
fstore.fst_posmode = F_PEOFPOSMODE;
|
||||||
|
} else if (mode & ALLOCATEFROMVOL) {
|
||||||
|
fstore.fst_posmode = F_VOLPOSMODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fstore.fst_offset = offset;
|
||||||
|
fstore.fst_length = length;
|
||||||
|
|
||||||
|
if (fcntl(fi->fh, F_PREALLOCATE, &fstore) == -1) {
|
||||||
|
return -errno;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_setvolname(const char *name)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_RENAMEX
|
||||||
|
|
||||||
|
static int
|
||||||
|
loopback_renamex(const char *path1, const char *path2, unsigned int flags)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = renamex_np(path1, path2, flags);
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_RENAMEX */
|
||||||
|
|
||||||
|
void *
|
||||||
|
loopback_init(struct fuse_conn_info *conn)
|
||||||
|
{
|
||||||
|
FUSE_ENABLE_SETVOLNAME(conn);
|
||||||
|
FUSE_ENABLE_XTIMES(conn);
|
||||||
|
|
||||||
|
#ifdef FUSE_ENABLE_CASE_INSENSITIVE
|
||||||
|
if (loopback.case_insensitive) {
|
||||||
|
FUSE_ENABLE_CASE_INSENSITIVE(conn);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
loopback_destroy(void *userdata)
|
||||||
|
{
|
||||||
|
/* nothing */
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct fuse_operations loopback_oper = {
|
||||||
|
.init = loopback_init,
|
||||||
|
.destroy = loopback_destroy,
|
||||||
|
.getattr = loopback_getattr,
|
||||||
|
.fgetattr = loopback_fgetattr,
|
||||||
|
/* .access = loopback_access, */
|
||||||
|
.readlink = loopback_readlink,
|
||||||
|
.opendir = loopback_opendir,
|
||||||
|
.readdir = loopback_readdir,
|
||||||
|
.releasedir = loopback_releasedir,
|
||||||
|
.mknod = loopback_mknod,
|
||||||
|
.mkdir = loopback_mkdir,
|
||||||
|
.symlink = loopback_symlink,
|
||||||
|
.unlink = loopback_unlink,
|
||||||
|
.rmdir = loopback_rmdir,
|
||||||
|
.rename = loopback_rename,
|
||||||
|
.link = loopback_link,
|
||||||
|
.create = loopback_create,
|
||||||
|
.open = loopback_open,
|
||||||
|
.read = loopback_read,
|
||||||
|
.write = loopback_write,
|
||||||
|
.statfs = loopback_statfs,
|
||||||
|
.flush = loopback_flush,
|
||||||
|
.release = loopback_release,
|
||||||
|
.fsync = loopback_fsync,
|
||||||
|
.setxattr = loopback_setxattr,
|
||||||
|
.getxattr = loopback_getxattr,
|
||||||
|
.listxattr = loopback_listxattr,
|
||||||
|
.removexattr = loopback_removexattr,
|
||||||
|
#if HAVE_EXCHANGE
|
||||||
|
.exchange = loopback_exchange,
|
||||||
|
#endif
|
||||||
|
.getxtimes = loopback_getxtimes,
|
||||||
|
.setattr_x = loopback_setattr_x,
|
||||||
|
.fsetattr_x = loopback_fsetattr_x,
|
||||||
|
.fallocate = loopback_fallocate,
|
||||||
|
.setvolname = loopback_setvolname,
|
||||||
|
#if HAVE_RENAMEX
|
||||||
|
.renamex = loopback_renamex,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.flag_nullpath_ok = 1,
|
||||||
|
.flag_nopath = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct fuse_opt loopback_opts[] = {
|
||||||
|
{ "case_insensitive", offsetof(struct loopback, case_insensitive), 1 },
|
||||||
|
FUSE_OPT_END
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
||||||
|
|
||||||
|
loopback.case_insensitive = 0;
|
||||||
|
if (fuse_opt_parse(&args, &loopback, loopback_opts, NULL) == -1) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
umask(0);
|
||||||
|
res = fuse_main(args.argc, args.argv, &loopback_oper, NULL);
|
||||||
|
|
||||||
|
fuse_opt_free_args(&args);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.cs.disable-library-validation</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
Copyright 2007-2008 Google Inc.
|
||||||
|
Copyright 2011-2021 Benjamin Fleischer
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
specific language governing permissions and limitations under the License.
|
||||||
|
|
@ -0,0 +1,360 @@
|
||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 45;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
43C857CB264AC68C0021A8BC /* macFUSE.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43C857CA264AC68C0021A8BC /* macFUSE.framework */; };
|
||||||
|
43E953A22646E241009CCB55 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43E953A02646E241009CCB55 /* MainMenu.xib */; };
|
||||||
|
43E953C62646F170009CCB55 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 43E953C52646F170009CCB55 /* Assets.xcassets */; };
|
||||||
|
8B93BEEF0D3ACD4400466F25 /* NSError+POSIX.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B93BEED0D3ACD4400466F25 /* NSError+POSIX.m */; };
|
||||||
|
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
|
||||||
|
FF8358230D24649E002F2357 /* LoopbackFS.m in Sources */ = {isa = PBXBuildFile; fileRef = FF8358220D24649E002F2357 /* LoopbackFS.m */; };
|
||||||
|
FF98B8B80D24909700117156 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FF98B8B70D24909700117156 /* AppDelegate.m */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||||
|
431DC7D2227DF080001A3694 /* LoopbackFS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LoopbackFS.entitlements; sourceTree = "<group>"; };
|
||||||
|
43C857CA264AC68C0021A8BC /* macFUSE.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = macFUSE.framework; path = ../../../../../../../Library/Frameworks/macFUSE.framework; sourceTree = "<group>"; };
|
||||||
|
43E9539D2646E1EA009CCB55 /* LICENSE.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE.txt; sourceTree = "<group>"; };
|
||||||
|
43E953A12646E241009CCB55 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||||
|
43E953C52646F170009CCB55 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
|
8B93BEED0D3ACD4400466F25 /* NSError+POSIX.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = "NSError+POSIX.m"; sourceTree = "<group>"; tabWidth = 2; };
|
||||||
|
8B93BEEE0D3ACD4400466F25 /* NSError+POSIX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = "NSError+POSIX.h"; sourceTree = "<group>"; tabWidth = 2; };
|
||||||
|
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
8D1107320486CEB800E47090 /* LoopbackFS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LoopbackFS.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
FF8358210D24649E002F2357 /* LoopbackFS.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = LoopbackFS.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||||
|
FF8358220D24649E002F2357 /* LoopbackFS.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = LoopbackFS.m; sourceTree = "<group>"; tabWidth = 2; };
|
||||||
|
FF98B8B60D24909700117156 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||||
|
FF98B8B70D24909700117156 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; tabWidth = 2; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
8D11072E0486CEB800E47090 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
43C857CB264AC68C0021A8BC /* macFUSE.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
080E96DDFE201D6D7F000001 /* LoopbackFS */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FF98B8B60D24909700117156 /* AppDelegate.h */,
|
||||||
|
FF98B8B70D24909700117156 /* AppDelegate.m */,
|
||||||
|
43E953C52646F170009CCB55 /* Assets.xcassets */,
|
||||||
|
8D1107310486CEB800E47090 /* Info.plist */,
|
||||||
|
431DC7D2227DF080001A3694 /* LoopbackFS.entitlements */,
|
||||||
|
FF8358210D24649E002F2357 /* LoopbackFS.h */,
|
||||||
|
FF8358220D24649E002F2357 /* LoopbackFS.m */,
|
||||||
|
29B97316FDCFA39411CA2CEA /* main.m */,
|
||||||
|
43E953A02646E241009CCB55 /* MainMenu.xib */,
|
||||||
|
8B93BEEE0D3ACD4400466F25 /* NSError+POSIX.h */,
|
||||||
|
8B93BEED0D3ACD4400466F25 /* NSError+POSIX.m */,
|
||||||
|
);
|
||||||
|
path = LoopbackFS;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
19C28FACFE9D520D11CA2CBB /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
8D1107320486CEB800E47090 /* LoopbackFS.app */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
29B97314FDCFA39411CA2CEA /* LoopbackFS */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
43E9539D2646E1EA009CCB55 /* LICENSE.txt */,
|
||||||
|
080E96DDFE201D6D7F000001 /* LoopbackFS */,
|
||||||
|
43C857C9264AC68C0021A8BC /* Frameworks */,
|
||||||
|
19C28FACFE9D520D11CA2CBB /* Products */,
|
||||||
|
);
|
||||||
|
name = LoopbackFS;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
43C857C9264AC68C0021A8BC /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
43C857CA264AC68C0021A8BC /* macFUSE.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
8D1107260486CEB800E47090 /* LoopbackFS */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "LoopbackFS" */;
|
||||||
|
buildPhases = (
|
||||||
|
8D11072C0486CEB800E47090 /* Sources */,
|
||||||
|
8D11072E0486CEB800E47090 /* Frameworks */,
|
||||||
|
8D1107290486CEB800E47090 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = LoopbackFS;
|
||||||
|
productInstallPath = "$(HOME)/Applications";
|
||||||
|
productName = LoopbackFS;
|
||||||
|
productReference = 8D1107320486CEB800E47090 /* LoopbackFS.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
LastUpgradeCheck = 1240;
|
||||||
|
TargetAttributes = {
|
||||||
|
8D1107260486CEB800E47090 = {
|
||||||
|
SystemCapabilities = {
|
||||||
|
com.apple.HardenedRuntime = {
|
||||||
|
enabled = 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "LoopbackFS" */;
|
||||||
|
compatibilityVersion = "Xcode 3.1";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 1;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 29B97314FDCFA39411CA2CEA /* LoopbackFS */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
8D1107260486CEB800E47090 /* LoopbackFS */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
8D1107290486CEB800E47090 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
43E953C62646F170009CCB55 /* Assets.xcassets in Resources */,
|
||||||
|
43E953A22646E241009CCB55 /* MainMenu.xib in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
8D11072C0486CEB800E47090 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
8D11072D0486CEB800E47090 /* main.m in Sources */,
|
||||||
|
FF8358230D24649E002F2357 /* LoopbackFS.m in Sources */,
|
||||||
|
FF98B8B80D24909700117156 /* AppDelegate.m in Sources */,
|
||||||
|
8B93BEEF0D3ACD4400466F25 /* NSError+POSIX.m in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXVariantGroup section */
|
||||||
|
43E953A02646E241009CCB55 /* MainMenu.xib */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
43E953A12646E241009CCB55 /* Base */,
|
||||||
|
);
|
||||||
|
name = MainMenu.xib;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
C01FCF4B08A954540054247B /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = NO;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = LoopbackFS/LoopbackFS.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = /Library/Frameworks;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
INFOPLIST_FILE = LoopbackFS/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "io.macfuse.demo.loopbackfs-objc";
|
||||||
|
PRODUCT_NAME = LoopbackFS;
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
WRAPPER_EXTENSION = app;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
C01FCF4C08A954540054247B /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = NO;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = LoopbackFS/LoopbackFS.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = /Library/Frameworks;
|
||||||
|
INFOPLIST_FILE = LoopbackFS/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "io.macfuse.demo.loopbackfs-objc";
|
||||||
|
PRODUCT_NAME = LoopbackFS;
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
WRAPPER_EXTENSION = app;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
C01FCF4F08A954540054247B /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
OTHER_CODE_SIGN_FLAGS = "--timestamp";
|
||||||
|
SDKROOT = macosx;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
C01FCF5008A954540054247B /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
OTHER_CODE_SIGN_FLAGS = "--timestamp";
|
||||||
|
SDKROOT = macosx;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "LoopbackFS" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
C01FCF4B08A954540054247B /* Debug */,
|
||||||
|
C01FCF4C08A954540054247B /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
C01FCF4E08A954540054247B /* Build configuration list for PBXProject "LoopbackFS" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
C01FCF4F08A954540054247B /* Debug */,
|
||||||
|
C01FCF5008A954540054247B /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1240"
|
||||||
|
version = "1.3">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "8D1107260486CEB800E47090"
|
||||||
|
BuildableName = "LoopbackFS.app"
|
||||||
|
BlueprintName = "LoopbackFS"
|
||||||
|
ReferencedContainer = "container:LoopbackFS.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "8D1107260486CEB800E47090"
|
||||||
|
BuildableName = "LoopbackFS.app"
|
||||||
|
BlueprintName = "LoopbackFS"
|
||||||
|
ReferencedContainer = "container:LoopbackFS.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<PreActions>
|
||||||
|
<ExecutionAction
|
||||||
|
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
|
||||||
|
<ActionContent
|
||||||
|
title = "Run Script"
|
||||||
|
scriptText = "# Unmount volumes umount -A -t "${OSXFUSE_NAME}" # Create source directory mkdir -p /tmp/dir">
|
||||||
|
</ActionContent>
|
||||||
|
</ExecutionAction>
|
||||||
|
</PreActions>
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "8D1107260486CEB800E47090"
|
||||||
|
BuildableName = "LoopbackFS.app"
|
||||||
|
BlueprintName = "LoopbackFS"
|
||||||
|
ReferencedContainer = "container:LoopbackFS.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "8D1107260486CEB800E47090"
|
||||||
|
BuildableName = "LoopbackFS.app"
|
||||||
|
BlueprintName = "LoopbackFS"
|
||||||
|
ReferencedContainer = "container:LoopbackFS.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// ================================================================
|
||||||
|
// Copyright (C) 2007 Google Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// ================================================================
|
||||||
|
//
|
||||||
|
// AppDelegate.h
|
||||||
|
// LoopbackFS
|
||||||
|
//
|
||||||
|
// Created by ted on 12/27/07.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <macFUSE/macFUSE.h>
|
||||||
|
|
||||||
|
#import "LoopbackFS.h"
|
||||||
|
|
||||||
|
@interface AppDelegate : NSObject {
|
||||||
|
GMUserFileSystem* fs_;
|
||||||
|
LoopbackFS* loop_;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
// ================================================================
|
||||||
|
// Copyright (C) 2007 Google Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// ================================================================
|
||||||
|
//
|
||||||
|
// AppDelegate.m
|
||||||
|
// LoopbackFS
|
||||||
|
//
|
||||||
|
// Created by ted on 12/27/07.
|
||||||
|
//
|
||||||
|
#import "AppDelegate.h"
|
||||||
|
|
||||||
|
#import <macFUSE/macFUSE.h>
|
||||||
|
|
||||||
|
#import <AvailabilityMacros.h>
|
||||||
|
|
||||||
|
#import "LoopbackFS.h"
|
||||||
|
|
||||||
|
static NSString *LoopbackMountPath = @"/Volumes/loop";
|
||||||
|
|
||||||
|
@implementation AppDelegate
|
||||||
|
|
||||||
|
- (void)mountFailed:(NSNotification *)notification {
|
||||||
|
NSLog(@"Got mountFailed notification.");
|
||||||
|
|
||||||
|
NSDictionary* userInfo = [notification userInfo];
|
||||||
|
NSError* error = [userInfo objectForKey:kGMUserFileSystemErrorKey];
|
||||||
|
NSLog(@"kGMUserFileSystem Error: %@, userInfo=%@", error, [error userInfo]);
|
||||||
|
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
NSAlert* alert = [[NSAlert alloc] init];
|
||||||
|
[alert setMessageText:@"Mount Failed"];
|
||||||
|
[alert setInformativeText:[error localizedDescription] ?: @"Unknown error"];
|
||||||
|
[alert runModal];
|
||||||
|
|
||||||
|
[[NSApplication sharedApplication] terminate:nil];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)didMount:(NSNotification *)notification {
|
||||||
|
NSLog(@"Got didMount notification.");
|
||||||
|
|
||||||
|
NSString *parentPath = [LoopbackMountPath stringByDeletingLastPathComponent];
|
||||||
|
[[NSWorkspace sharedWorkspace] selectFile:LoopbackMountPath
|
||||||
|
inFileViewerRootedAtPath:parentPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)didUnmount:(NSNotification*)notification {
|
||||||
|
NSLog(@"Got didUnmount notification.");
|
||||||
|
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[[NSApplication sharedApplication] terminate:nil];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
|
||||||
|
NSOpenPanel* panel = [NSOpenPanel openPanel];
|
||||||
|
[panel setCanChooseFiles:NO];
|
||||||
|
[panel setCanChooseDirectories:YES];
|
||||||
|
[panel setAllowsMultipleSelection:NO];
|
||||||
|
[panel setDirectoryURL:[NSURL fileURLWithPath:@"/tmp"]];
|
||||||
|
NSModalResponse ret = [panel runModal];
|
||||||
|
|
||||||
|
if ( ret == NSModalResponseCancel ) {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
NSArray* paths = [panel URLs];
|
||||||
|
if ( [paths count] != 1 ) {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
NSString* rootPath = nil;
|
||||||
|
rootPath = [[paths objectAtIndex:0] path];
|
||||||
|
|
||||||
|
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
|
||||||
|
[center addObserver:self selector:@selector(mountFailed:)
|
||||||
|
name:kGMUserFileSystemMountFailed object:nil];
|
||||||
|
[center addObserver:self selector:@selector(didMount:)
|
||||||
|
name:kGMUserFileSystemDidMount object:nil];
|
||||||
|
[center addObserver:self selector:@selector(didUnmount:)
|
||||||
|
name:kGMUserFileSystemDidUnmount object:nil];
|
||||||
|
|
||||||
|
loop_ = [[LoopbackFS alloc] initWithRootPath:rootPath];
|
||||||
|
|
||||||
|
fs_ = [[GMUserFileSystem alloc] initWithDelegate:loop_ isThreadSafe:NO];
|
||||||
|
|
||||||
|
NSMutableArray* options = [NSMutableArray array];
|
||||||
|
|
||||||
|
// Do not use the 'native_xattr' mount-time option unless the underlying
|
||||||
|
// file system supports native extended attributes. Typically, the user
|
||||||
|
// would be mounting an HFS+ directory through LoopbackFS, so we do want
|
||||||
|
// this option in that case.
|
||||||
|
[options addObject:@"native_xattr"];
|
||||||
|
|
||||||
|
[options addObject:@"volname=LoopbackFS"];
|
||||||
|
[fs_ mountAtPath:LoopbackMountPath
|
||||||
|
withOptions:options];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
[fs_ unmount];
|
||||||
|
[fs_ release];
|
||||||
|
[loop_ release];
|
||||||
|
return NSTerminateNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "512x512"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "512x512"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,680 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="macosx"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17701"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
|
||||||
|
</connections>
|
||||||
|
</customObject>
|
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
|
<customObject id="-3" userLabel="Application"/>
|
||||||
|
<customObject id="Voe-Tx-rLC" customClass="AppDelegate"/>
|
||||||
|
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||||
|
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
||||||
|
<items>
|
||||||
|
<menuItem title="LoopbackFS" id="1Xt-HY-uBw">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="LoopbackFS" systemMenu="apple" id="uQy-DD-JDr">
|
||||||
|
<items>
|
||||||
|
<menuItem title="About LoopbackFS" id="5kV-Vb-QxS">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
||||||
|
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
|
||||||
|
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
|
||||||
|
<menuItem title="Services" id="NMo-om-nkz">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
|
||||||
|
<menuItem title="Hide LoopbackFS" keyEquivalent="h" id="Olw-nP-bQN">
|
||||||
|
<connections>
|
||||||
|
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Show All" id="Kd2-mp-pUS">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
|
||||||
|
<menuItem title="Quit LoopbackFS" keyEquivalent="q" id="4sb-4s-VLi">
|
||||||
|
<connections>
|
||||||
|
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="File" id="dMs-cI-mzQ">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="File" id="bib-Uj-vzu">
|
||||||
|
<items>
|
||||||
|
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
|
||||||
|
<connections>
|
||||||
|
<action selector="newDocument:" target="-1" id="4Si-XN-c54"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
|
||||||
|
<connections>
|
||||||
|
<action selector="openDocument:" target="-1" id="bVn-NM-KNZ"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Open Recent" id="tXI-mr-wws">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Clear Menu" id="vNY-rz-j42">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="clearRecentDocuments:" target="-1" id="Daa-9d-B3U"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
|
||||||
|
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
|
||||||
|
<connections>
|
||||||
|
<action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
|
||||||
|
<connections>
|
||||||
|
<action selector="saveDocument:" target="-1" id="teZ-XB-qJY"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
|
||||||
|
<connections>
|
||||||
|
<action selector="saveDocumentAs:" target="-1" id="mDf-zr-I0C"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H">
|
||||||
|
<connections>
|
||||||
|
<action selector="revertDocumentToSaved:" target="-1" id="iJ3-Pv-kwq"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
|
||||||
|
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="runPageLayout:" target="-1" id="Din-rz-gC5"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
|
||||||
|
<connections>
|
||||||
|
<action selector="print:" target="-1" id="qaZ-4w-aoO"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Edit" id="5QF-Oa-p0T">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
|
||||||
|
<connections>
|
||||||
|
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
|
||||||
|
<connections>
|
||||||
|
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
|
||||||
|
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
|
||||||
|
<connections>
|
||||||
|
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
|
||||||
|
<connections>
|
||||||
|
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
|
||||||
|
<connections>
|
||||||
|
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Delete" id="pa3-QI-u2k">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
|
||||||
|
<connections>
|
||||||
|
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
|
||||||
|
<menuItem title="Find" id="4EN-yA-p0u">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Find" id="1b7-l0-nxx">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
|
||||||
|
<connections>
|
||||||
|
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
|
||||||
|
<connections>
|
||||||
|
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
|
||||||
|
<connections>
|
||||||
|
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
|
||||||
|
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Substitutions" id="9ic-FL-obx">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
|
||||||
|
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Smart Links" id="cwL-P1-jid">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Data Detectors" id="tRr-pd-1PS">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Transformations" id="2oI-Rn-ZJC">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Speech" id="xrE-MZ-jX0">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Format" id="jxT-CU-nIS">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Format" id="GEO-Iw-cKr">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Font" id="Gi5-1S-RQB">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq">
|
||||||
|
<connections>
|
||||||
|
<action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27">
|
||||||
|
<connections>
|
||||||
|
<action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq">
|
||||||
|
<connections>
|
||||||
|
<action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
|
||||||
|
<connections>
|
||||||
|
<action selector="underline:" target="-1" id="FYS-2b-JAY"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
|
||||||
|
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL">
|
||||||
|
<connections>
|
||||||
|
<action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST">
|
||||||
|
<connections>
|
||||||
|
<action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
|
||||||
|
<menuItem title="Kern" id="jBQ-r6-VK2">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Kern" id="tlD-Oa-oAM">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Use Default" id="GUa-eO-cwY">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="useStandardKerning:" target="-1" id="6dk-9l-Ckg"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Use None" id="cDB-IK-hbR">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="turnOffKerning:" target="-1" id="U8a-gz-Maa"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Tighten" id="46P-cB-AYj">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="tightenKerning:" target="-1" id="hr7-Nz-8ro"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Loosen" id="ogc-rX-tC1">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="loosenKerning:" target="-1" id="8i4-f9-FKE"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Ligatures" id="o6e-r0-MWq">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Use Default" id="agt-UL-0e3">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="useStandardLigatures:" target="-1" id="7uR-wd-Dx6"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Use None" id="J7y-lM-qPV">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="turnOffLigatures:" target="-1" id="iX2-gA-Ilz"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Use All" id="xQD-1f-W4t">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="useAllLigatures:" target="-1" id="KcB-kA-TuK"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Baseline" id="OaQ-X3-Vso">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Baseline" id="ijk-EB-dga">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Use Default" id="3Om-Ey-2VK">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="unscript:" target="-1" id="0vZ-95-Ywn"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Superscript" id="Rqc-34-cIF">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="superscript:" target="-1" id="3qV-fo-wpU"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Subscript" id="I0S-gh-46l">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="subscript:" target="-1" id="Q6W-4W-IGz"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Raise" id="2h7-ER-AoG">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="raiseBaseline:" target="-1" id="4sk-31-7Q9"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Lower" id="1tx-W0-xDw">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="lowerBaseline:" target="-1" id="OF1-bc-KW4"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
|
||||||
|
<menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
|
||||||
|
<connections>
|
||||||
|
<action selector="orderFrontColorPanel:" target="-1" id="mSX-Xz-DV3"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
|
||||||
|
<menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="copyFont:" target="-1" id="GJO-xA-L4q"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="pasteFont:" target="-1" id="JfD-CL-leO"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Text" id="Fal-I4-PZk">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Text" id="d9c-me-L2H">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
|
||||||
|
<connections>
|
||||||
|
<action selector="alignLeft:" target="-1" id="zUv-R1-uAa"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
|
||||||
|
<connections>
|
||||||
|
<action selector="alignCenter:" target="-1" id="spX-mk-kcS"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Justify" id="J5U-5w-g23">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="alignJustified:" target="-1" id="ljL-7U-jND"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
|
||||||
|
<connections>
|
||||||
|
<action selector="alignRight:" target="-1" id="r48-bG-YeY"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
|
||||||
|
<menuItem title="Writing Direction" id="H1b-Si-o9J">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem id="YGs-j5-SAR">
|
||||||
|
<string key="title"> Default</string>
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="makeBaseWritingDirectionNatural:" target="-1" id="qtV-5e-UBP"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem id="Lbh-J2-qVU">
|
||||||
|
<string key="title"> Left to Right</string>
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="makeBaseWritingDirectionLeftToRight:" target="-1" id="S0X-9S-QSf"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem id="jFq-tB-4Kx">
|
||||||
|
<string key="title"> Right to Left</string>
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="makeBaseWritingDirectionRightToLeft:" target="-1" id="5fk-qB-AqJ"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
|
||||||
|
<menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem id="Nop-cj-93Q">
|
||||||
|
<string key="title"> Default</string>
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="makeTextWritingDirectionNatural:" target="-1" id="lPI-Se-ZHp"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem id="BgM-ve-c93">
|
||||||
|
<string key="title"> Left to Right</string>
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="makeTextWritingDirectionLeftToRight:" target="-1" id="caW-Bv-w94"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem id="RB4-Sm-HuC">
|
||||||
|
<string key="title"> Right to Left</string>
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="makeTextWritingDirectionRightToLeft:" target="-1" id="EXD-6r-ZUu"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
|
||||||
|
<menuItem title="Show Ruler" id="vLm-3I-IUL">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleRuler:" target="-1" id="FOx-HJ-KwY"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="copyRuler:" target="-1" id="71i-fW-3W2"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="pasteRuler:" target="-1" id="cSh-wd-qM2"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="View" id="H8h-7b-M4v">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="View" id="HyV-fh-RgO">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleToolbarShown:" target="-1" id="BXY-wc-z0C"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="runToolbarCustomizationPalette:" target="-1" id="pQI-g3-MTW"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
|
||||||
|
<menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleSidebar:" target="-1" id="iwa-gc-5KM"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Window" id="aUF-d1-5bR">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
|
||||||
|
<connections>
|
||||||
|
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Zoom" id="R4o-n2-Eq4">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
|
||||||
|
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Help" id="wpr-3q-Mcd">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
|
||||||
|
<items>
|
||||||
|
<menuItem title="LoopbackFS Help" keyEquivalent="?" id="FKE-Sm-Kum" userLabel="Loopback Help">
|
||||||
|
<connections>
|
||||||
|
<action selector="showHelp:" target="-1" id="y7X-2Q-9no"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
<point key="canvasLocation" x="31" y="154"/>
|
||||||
|
</menu>
|
||||||
|
</objects>
|
||||||
|
</document>
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>${EXECUTABLE_NAME}</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>${PRODUCT_NAME}</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>NSMainNibFile</key>
|
||||||
|
<string>MainMenu</string>
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string>NSApplication</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.cs.disable-library-validation</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// ================================================================
|
||||||
|
// Copyright (C) 2007 Google Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// ================================================================
|
||||||
|
//
|
||||||
|
// LoopbackFS.h
|
||||||
|
// LoopbackFS
|
||||||
|
//
|
||||||
|
// Created by ted on 12/12/07.
|
||||||
|
//
|
||||||
|
// This is a simple but complete example filesystem that mounts a local
|
||||||
|
// directory. You can modify this to see how the Finder reacts to returning
|
||||||
|
// specific error codes or not implementing a particular GMUserFileSystem
|
||||||
|
// operation.
|
||||||
|
//
|
||||||
|
// For example, you can mount "/tmp" in /Volumes/loop. Note: It is
|
||||||
|
// probably not a good idea to mount "/" through this filesystem.
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface LoopbackFS : NSObject {
|
||||||
|
NSString* rootPath_; // The local file-system path to mount.
|
||||||
|
}
|
||||||
|
- (id)initWithRootPath:(NSString *)rootPath;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
@ -0,0 +1,479 @@
|
||||||
|
// ================================================================
|
||||||
|
// Copyright (C) 2007 Google Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// ================================================================
|
||||||
|
//
|
||||||
|
// LoopbackFS.m
|
||||||
|
// LoopbackFS
|
||||||
|
//
|
||||||
|
// Created by ted on 12/12/07.
|
||||||
|
//
|
||||||
|
// This is a simple but complete example filesystem that mounts a local
|
||||||
|
// directory. You can modify this to see how the Finder reacts to returning
|
||||||
|
// specific error codes or not implementing a particular GMUserFileSystem
|
||||||
|
// operation.
|
||||||
|
//
|
||||||
|
// For example, you can mount "/tmp" in /Volumes/loop. Note: It is
|
||||||
|
// probably not a good idea to mount "/" through this filesystem.
|
||||||
|
|
||||||
|
#import "LoopbackFS.h"
|
||||||
|
|
||||||
|
#import <macFUSE/macFUSE.h>
|
||||||
|
|
||||||
|
#import <sys/stat.h>
|
||||||
|
#import <sys/vnode.h>
|
||||||
|
#import <sys/xattr.h>
|
||||||
|
|
||||||
|
#import "NSError+POSIX.h"
|
||||||
|
|
||||||
|
#define HAVE_EXCHANE 0
|
||||||
|
|
||||||
|
@implementation LoopbackFS
|
||||||
|
|
||||||
|
- (id)initWithRootPath:(NSString *)rootPath {
|
||||||
|
if ((self = [super init])) {
|
||||||
|
rootPath_ = [rootPath retain];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc {
|
||||||
|
[rootPath_ release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Moving an Item
|
||||||
|
|
||||||
|
- (BOOL)moveItemAtPath:(NSString *)source
|
||||||
|
toPath:(NSString *)destination
|
||||||
|
options:(GMUserFileSystemMoveOption)options
|
||||||
|
error:(NSError **)error {
|
||||||
|
// We use rename directly here since NSFileManager can sometimes fail to
|
||||||
|
// rename and return non-posix error codes.
|
||||||
|
NSString* p_src = [rootPath_ stringByAppendingString:source];
|
||||||
|
NSString* p_dst = [rootPath_ stringByAppendingString:destination];
|
||||||
|
int ret = 0;
|
||||||
|
if (options == 0) {
|
||||||
|
ret = rename([p_src UTF8String], [p_dst UTF8String]);
|
||||||
|
} else {
|
||||||
|
unsigned int flags = 0;
|
||||||
|
if (options & GMUserFileSystemMoveOptionSwap) {
|
||||||
|
flags |= RENAME_SWAP;
|
||||||
|
}
|
||||||
|
if (options & GMUserFileSystemMoveOptionExclusive) {
|
||||||
|
flags |= RENAME_EXCL;
|
||||||
|
}
|
||||||
|
ret = renamex_np([p_src UTF8String], [p_dst UTF8String], flags);
|
||||||
|
}
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Removing an Item
|
||||||
|
|
||||||
|
- (BOOL)removeDirectoryAtPath:(NSString *)path error:(NSError **)error {
|
||||||
|
// We need to special-case directories here and use the bsd API since
|
||||||
|
// NSFileManager will happily do a recursive remove :-(
|
||||||
|
NSString* p = [rootPath_ stringByAppendingString:path];
|
||||||
|
int ret = rmdir([p UTF8String]);
|
||||||
|
if (ret < 0) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error {
|
||||||
|
// NOTE: If removeDirectoryAtPath is commented out, then this may be called
|
||||||
|
// with a directory, in which case NSFileManager will recursively remove all
|
||||||
|
// subdirectories. So be careful!
|
||||||
|
NSString* p = [rootPath_ stringByAppendingString:path];
|
||||||
|
return [[NSFileManager defaultManager] removeItemAtPath:p error:error];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Creating an Item
|
||||||
|
|
||||||
|
- (BOOL)createDirectoryAtPath:(NSString *)path
|
||||||
|
attributes:(NSDictionary *)attributes
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSString* p = [rootPath_ stringByAppendingString:path];
|
||||||
|
return [[NSFileManager defaultManager] createDirectoryAtPath:p
|
||||||
|
withIntermediateDirectories:NO
|
||||||
|
attributes:attributes
|
||||||
|
error:error];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)createFileAtPath:(NSString *)path
|
||||||
|
attributes:(NSDictionary *)attributes
|
||||||
|
flags:(int)flags
|
||||||
|
userData:(id *)userData
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSString* p = [rootPath_ stringByAppendingString:path];
|
||||||
|
mode_t mode = [[attributes objectForKey:NSFilePosixPermissions] longValue];
|
||||||
|
int fd = open([p UTF8String], flags, mode);
|
||||||
|
if ( fd < 0 ) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
*userData = [NSNumber numberWithLong:fd];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Linking an Item
|
||||||
|
|
||||||
|
- (BOOL)linkItemAtPath:(NSString *)path
|
||||||
|
toPath:(NSString *)otherPath
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSString* p_path = [rootPath_ stringByAppendingString:path];
|
||||||
|
NSString* p_otherPath = [rootPath_ stringByAppendingString:otherPath];
|
||||||
|
|
||||||
|
// We use link rather than the NSFileManager equivalent because it will copy
|
||||||
|
// the file rather than hard link if part of the root path is a symlink.
|
||||||
|
int rc = link([p_path UTF8String], [p_otherPath UTF8String]);
|
||||||
|
if ( rc < 0 ) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Symbolic Links
|
||||||
|
|
||||||
|
- (BOOL)createSymbolicLinkAtPath:(NSString *)path
|
||||||
|
withDestinationPath:(NSString *)otherPath
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSString* p_src = [rootPath_ stringByAppendingString:path];
|
||||||
|
return [[NSFileManager defaultManager] createSymbolicLinkAtPath:p_src
|
||||||
|
withDestinationPath:otherPath
|
||||||
|
error:error];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)destinationOfSymbolicLinkAtPath:(NSString *)path
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSString* p = [rootPath_ stringByAppendingString:path];
|
||||||
|
return [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:p
|
||||||
|
error:error];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark File Contents
|
||||||
|
|
||||||
|
- (BOOL)openFileAtPath:(NSString *)path
|
||||||
|
mode:(int)mode
|
||||||
|
userData:(id *)userData
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSString* p = [rootPath_ stringByAppendingString:path];
|
||||||
|
int fd = open([p UTF8String], mode);
|
||||||
|
if ( fd < 0 ) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
*userData = [NSNumber numberWithLong:fd];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)releaseFileAtPath:(NSString *)path userData:(id)userData {
|
||||||
|
NSNumber* num = (NSNumber *)userData;
|
||||||
|
int fd = [num intValue];
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)readFileAtPath:(NSString *)path
|
||||||
|
userData:(id)userData
|
||||||
|
buffer:(char *)buffer
|
||||||
|
size:(size_t)size
|
||||||
|
offset:(off_t)offset
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSNumber* num = (NSNumber *)userData;
|
||||||
|
int fd = [num intValue];
|
||||||
|
size_t ret = pread(fd, buffer, size, offset);
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return (int)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)writeFileAtPath:(NSString *)path
|
||||||
|
userData:(id)userData
|
||||||
|
buffer:(const char *)buffer
|
||||||
|
size:(size_t)size
|
||||||
|
offset:(off_t)offset
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSNumber* num = (NSNumber *)userData;
|
||||||
|
int fd = [num intValue];
|
||||||
|
size_t ret = pwrite(fd, buffer, size, offset);
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return (int)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)preallocateFileAtPath:(NSString *)path
|
||||||
|
userData:(id)userData
|
||||||
|
options:(int)options
|
||||||
|
offset:(off_t)offset
|
||||||
|
length:(off_t)length
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSNumber* num = (NSNumber *)userData;
|
||||||
|
int fd = [num intValue];
|
||||||
|
|
||||||
|
fstore_t fstore;
|
||||||
|
|
||||||
|
fstore.fst_flags = 0;
|
||||||
|
if ( options & ALLOCATECONTIG ) {
|
||||||
|
fstore.fst_flags |= F_ALLOCATECONTIG;
|
||||||
|
}
|
||||||
|
if ( options & ALLOCATEALL ) {
|
||||||
|
fstore.fst_flags |= F_ALLOCATEALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( options & ALLOCATEFROMPEOF ) {
|
||||||
|
fstore.fst_posmode = F_PEOFPOSMODE;
|
||||||
|
} else if ( options & ALLOCATEFROMVOL ) {
|
||||||
|
fstore.fst_posmode = F_VOLPOSMODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fstore.fst_offset = offset;
|
||||||
|
fstore.fst_length = length;
|
||||||
|
|
||||||
|
if ( fcntl(fd, F_PREALLOCATE, &fstore) == -1 ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_EXCHANE
|
||||||
|
|
||||||
|
- (BOOL)exchangeDataOfItemAtPath:(NSString *)path1
|
||||||
|
withItemAtPath:(NSString *)path2
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSString* p1 = [rootPath_ stringByAppendingString:path1];
|
||||||
|
NSString* p2 = [rootPath_ stringByAppendingString:path2];
|
||||||
|
int ret = exchangedata([p1 UTF8String], [p2 UTF8String], 0);
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_EXCHANGE */
|
||||||
|
|
||||||
|
#pragma mark Directory Contents
|
||||||
|
|
||||||
|
- (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error {
|
||||||
|
NSString* p = [rootPath_ stringByAppendingString:path];
|
||||||
|
return [[NSFileManager defaultManager] contentsOfDirectoryAtPath:p error:error];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Getting and Setting Attributes
|
||||||
|
|
||||||
|
- (NSDictionary *)attributesOfItemAtPath:(NSString *)path
|
||||||
|
userData:(id)userData
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSString* p = [rootPath_ stringByAppendingString:path];
|
||||||
|
NSDictionary* attribs =
|
||||||
|
[[NSFileManager defaultManager] attributesOfItemAtPath:p error:error];
|
||||||
|
return attribs;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSDictionary *)attributesOfFileSystemForPath:(NSString *)path
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSString* p = [rootPath_ stringByAppendingString:path];
|
||||||
|
NSDictionary* d =
|
||||||
|
[[NSFileManager defaultManager] attributesOfFileSystemForPath:p error:error];
|
||||||
|
if (d) {
|
||||||
|
NSMutableDictionary* attribs = [NSMutableDictionary dictionaryWithDictionary:d];
|
||||||
|
[attribs setObject:[NSNumber numberWithBool:YES]
|
||||||
|
forKey:kGMUserFileSystemVolumeSupportsExtendedDatesKey];
|
||||||
|
|
||||||
|
NSURL *URL = [NSURL fileURLWithPath:p isDirectory:YES];
|
||||||
|
NSNumber *supportsCaseSensitiveNames = nil;
|
||||||
|
[URL getResourceValue:&supportsCaseSensitiveNames
|
||||||
|
forKey:NSURLVolumeSupportsCaseSensitiveNamesKey
|
||||||
|
error:NULL];
|
||||||
|
if (supportsCaseSensitiveNames == nil) {
|
||||||
|
supportsCaseSensitiveNames = [NSNumber numberWithBool:YES];
|
||||||
|
}
|
||||||
|
[attribs setObject:supportsCaseSensitiveNames
|
||||||
|
forKey:kGMUserFileSystemVolumeSupportsCaseSensitiveNamesKey];
|
||||||
|
|
||||||
|
[attribs setObject:[NSNumber numberWithBool:YES]
|
||||||
|
forKey:kGMUserFileSystemVolumeSupportsSwapRenamingKey];
|
||||||
|
[attribs setObject:[NSNumber numberWithBool:YES]
|
||||||
|
forKey:kGMUserFileSystemVolumeSupportsExclusiveRenamingKey];
|
||||||
|
|
||||||
|
[attribs setObject:[NSNumber numberWithBool:YES]
|
||||||
|
forKey:kGMUserFileSystemVolumeSupportsSetVolumeNameKey];
|
||||||
|
|
||||||
|
return attribs;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)setAttributes:(NSDictionary *)attributes
|
||||||
|
ofItemAtPath:(NSString *)path
|
||||||
|
userData:(id)userData
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSString* p = [rootPath_ stringByAppendingString:path];
|
||||||
|
|
||||||
|
// TODO: Handle other keys not handled by NSFileManager setAttributes call.
|
||||||
|
|
||||||
|
NSNumber* offset = [attributes objectForKey:NSFileSize];
|
||||||
|
if ( offset ) {
|
||||||
|
int ret = truncate([p UTF8String], [offset longLongValue]);
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSNumber* flags = [attributes objectForKey:kGMUserFileSystemFileFlagsKey];
|
||||||
|
if (flags != nil) {
|
||||||
|
int rc = chflags([p UTF8String], [flags intValue]);
|
||||||
|
if (rc < 0) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [[NSFileManager defaultManager] setAttributes:attributes
|
||||||
|
ofItemAtPath:p
|
||||||
|
error:error];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)setAttributes:(NSDictionary *)attributes
|
||||||
|
ofFileSystemAtPath:(NSString *)path
|
||||||
|
error:(NSError **)error {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Extended Attributes
|
||||||
|
|
||||||
|
- (NSArray *)extendedAttributesOfItemAtPath:(NSString *)path error:(NSError **)error {
|
||||||
|
NSString* p = [rootPath_ stringByAppendingString:path];
|
||||||
|
|
||||||
|
ssize_t size = listxattr([p UTF8String], nil, 0, XATTR_NOFOLLOW);
|
||||||
|
if ( size < 0 ) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
NSMutableData* data = [NSMutableData dataWithLength:size];
|
||||||
|
size = listxattr([p UTF8String], [data mutableBytes], [data length], XATTR_NOFOLLOW);
|
||||||
|
if ( size < 0 ) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
NSMutableArray* contents = [NSMutableArray array];
|
||||||
|
char* ptr = (char *)[data bytes];
|
||||||
|
while ( ptr < ((char *)[data bytes] + size) ) {
|
||||||
|
NSString* s = [NSString stringWithUTF8String:ptr];
|
||||||
|
[contents addObject:s];
|
||||||
|
ptr += ([s length] + 1);
|
||||||
|
}
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSData *)valueOfExtendedAttribute:(NSString *)name
|
||||||
|
ofItemAtPath:(NSString *)path
|
||||||
|
position:(off_t)position
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSString* p = [rootPath_ stringByAppendingString:path];
|
||||||
|
|
||||||
|
ssize_t size = getxattr([p UTF8String], [name UTF8String], nil, 0,
|
||||||
|
(uint32_t)position, XATTR_NOFOLLOW);
|
||||||
|
if ( size < 0 ) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
NSMutableData* data = [NSMutableData dataWithLength:size];
|
||||||
|
size = getxattr([p UTF8String], [name UTF8String], [data mutableBytes],
|
||||||
|
[data length], (uint32_t)position, XATTR_NOFOLLOW);
|
||||||
|
if ( size < 0 ) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)setExtendedAttribute:(NSString *)name
|
||||||
|
ofItemAtPath:(NSString *)path
|
||||||
|
value:(NSData *)value
|
||||||
|
position:(off_t)position
|
||||||
|
options:(int)options
|
||||||
|
error:(NSError **)error {
|
||||||
|
// Setting com.apple.FinderInfo happens in the kernel, so security related
|
||||||
|
// bits are set in the options. We need to explicitly remove them or the call
|
||||||
|
// to setxattr will fail.
|
||||||
|
// TODO: Why is this necessary?
|
||||||
|
options &= ~(XATTR_NOSECURITY | XATTR_NODEFAULT);
|
||||||
|
NSString* p = [rootPath_ stringByAppendingString:path];
|
||||||
|
int ret = setxattr([p UTF8String], [name UTF8String], [value bytes],
|
||||||
|
[value length], (uint32_t)position,
|
||||||
|
options | XATTR_NOFOLLOW);
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)removeExtendedAttribute:(NSString *)name
|
||||||
|
ofItemAtPath:(NSString *)path
|
||||||
|
error:(NSError **)error {
|
||||||
|
NSString* p = [rootPath_ stringByAppendingString:path];
|
||||||
|
int ret = removexattr([p UTF8String], [name UTF8String], XATTR_NOFOLLOW);
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
if ( error ) {
|
||||||
|
*error = [NSError errorWithPOSIXCode:errno];
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
//
|
||||||
|
// NSError+POSIX.h
|
||||||
|
//
|
||||||
|
// ================================================================
|
||||||
|
// Copyright (C) 2008 Google Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// ================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
// Category on NSError to simplify creating an NSError based on posix errno.
|
||||||
|
@interface NSError (POSIX)
|
||||||
|
+ (NSError *)errorWithPOSIXCode:(int)code;
|
||||||
|
@end
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// NSError+POSIX.m
|
||||||
|
//
|
||||||
|
// ================================================================
|
||||||
|
// Copyright (C) 2008 Google Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// ================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NSError+POSIX.h"
|
||||||
|
|
||||||
|
@implementation NSError (POSIX)
|
||||||
|
+ (NSError *)errorWithPOSIXCode:(int) code {
|
||||||
|
return [NSError errorWithDomain:NSPOSIXErrorDomain code:code userInfo:nil];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// ================================================================
|
||||||
|
// Copyright (C) 2007 Google Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// ================================================================
|
||||||
|
//
|
||||||
|
// main.m
|
||||||
|
// LoopbackFS
|
||||||
|
//
|
||||||
|
// Created by ted on 12/27/07.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
int main(int argc, const char * argv[]) {
|
||||||
|
@autoreleasepool {
|
||||||
|
// Setup code that might create autoreleased objects goes here.
|
||||||
|
}
|
||||||
|
return NSApplicationMain(argc, argv);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright 2017 KF Interactive GmbH
|
||||||
|
Copyright 2018-2021 Benjamin Fleischer
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
@ -0,0 +1,360 @@
|
||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 46;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
43C857D8264ACAAE0021A8BC /* macFUSE.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43C857D7264ACAAE0021A8BC /* macFUSE.framework */; };
|
||||||
|
43E9539A2646E19C009CCB55 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 43E953992646E19C009CCB55 /* Assets.xcassets */; };
|
||||||
|
F48D00F31E3B6EC000FE033E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F48D00F21E3B6EC000FE033E /* AppDelegate.swift */; };
|
||||||
|
F48D00F81E3B6EC000FE033E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F48D00F61E3B6EC000FE033E /* MainMenu.xib */; };
|
||||||
|
F48D01071E3B74F900FE033E /* LoopbackFS.swift in Sources */ = {isa = PBXBuildFile; fileRef = F48D01061E3B74F900FE033E /* LoopbackFS.swift */; };
|
||||||
|
F48D01091E3B7DA500FE033E /* NSError+POSIX.swift in Sources */ = {isa = PBXBuildFile; fileRef = F48D01081E3B7DA500FE033E /* NSError+POSIX.swift */; };
|
||||||
|
F4D7409B1E65585B007D6E11 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = F4D7409A1E65585B007D6E11 /* LICENSE.txt */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
43C857D7264ACAAE0021A8BC /* macFUSE.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = macFUSE.framework; path = ../../../../../../../Library/Frameworks/macFUSE.framework; sourceTree = "<group>"; };
|
||||||
|
43E953992646E19C009CCB55 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
|
43EBE3672360F9D300E3A7F5 /* LoopbackFS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LoopbackFS.entitlements; sourceTree = "<group>"; };
|
||||||
|
F48D00EF1E3B6EC000FE033E /* LoopbackFS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LoopbackFS.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
F48D00F21E3B6EC000FE033E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
F48D00F71E3B6EC000FE033E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||||
|
F48D00F91E3B6EC000FE033E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
F48D01051E3B716E00FE033E /* Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
|
F48D01061E3B74F900FE033E /* LoopbackFS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoopbackFS.swift; sourceTree = "<group>"; };
|
||||||
|
F48D01081E3B7DA500FE033E /* NSError+POSIX.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSError+POSIX.swift"; sourceTree = "<group>"; };
|
||||||
|
F4D7409A1E65585B007D6E11 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
F48D00EC1E3B6EC000FE033E /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
43C857D8264ACAAE0021A8BC /* macFUSE.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
43C857D6264ACAAE0021A8BC /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
43C857D7264ACAAE0021A8BC /* macFUSE.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F48D00E61E3B6EC000FE033E = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F4D7409A1E65585B007D6E11 /* LICENSE.txt */,
|
||||||
|
F48D00F11E3B6EC000FE033E /* LoopbackFS */,
|
||||||
|
43C857D6264ACAAE0021A8BC /* Frameworks */,
|
||||||
|
F48D00F01E3B6EC000FE033E /* Products */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F48D00F01E3B6EC000FE033E /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F48D00EF1E3B6EC000FE033E /* LoopbackFS.app */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F48D00F11E3B6EC000FE033E /* LoopbackFS */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F48D00F21E3B6EC000FE033E /* AppDelegate.swift */,
|
||||||
|
43E953992646E19C009CCB55 /* Assets.xcassets */,
|
||||||
|
F48D01051E3B716E00FE033E /* Bridging-Header.h */,
|
||||||
|
F48D00F91E3B6EC000FE033E /* Info.plist */,
|
||||||
|
43EBE3672360F9D300E3A7F5 /* LoopbackFS.entitlements */,
|
||||||
|
F48D01061E3B74F900FE033E /* LoopbackFS.swift */,
|
||||||
|
F48D00F61E3B6EC000FE033E /* MainMenu.xib */,
|
||||||
|
F48D01081E3B7DA500FE033E /* NSError+POSIX.swift */,
|
||||||
|
);
|
||||||
|
path = LoopbackFS;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
F48D00EE1E3B6EC000FE033E /* LoopbackFS */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = F48D00FC1E3B6EC000FE033E /* Build configuration list for PBXNativeTarget "LoopbackFS" */;
|
||||||
|
buildPhases = (
|
||||||
|
F48D00EB1E3B6EC000FE033E /* Sources */,
|
||||||
|
F48D00EC1E3B6EC000FE033E /* Frameworks */,
|
||||||
|
F48D00ED1E3B6EC000FE033E /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = LoopbackFS;
|
||||||
|
productName = LoopbackFS;
|
||||||
|
productReference = F48D00EF1E3B6EC000FE033E /* LoopbackFS.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
F48D00E71E3B6EC000FE033E /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
LastSwiftUpdateCheck = 0820;
|
||||||
|
LastUpgradeCheck = 1240;
|
||||||
|
ORGANIZATIONNAME = "KF Interactive GmbH";
|
||||||
|
TargetAttributes = {
|
||||||
|
F48D00EE1E3B6EC000FE033E = {
|
||||||
|
CreatedOnToolsVersion = 8.2.1;
|
||||||
|
LastSwiftMigration = 1240;
|
||||||
|
ProvisioningStyle = Manual;
|
||||||
|
SystemCapabilities = {
|
||||||
|
com.apple.HardenedRuntime = {
|
||||||
|
enabled = 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = F48D00EA1E3B6EC000FE033E /* Build configuration list for PBXProject "LoopbackFS" */;
|
||||||
|
compatibilityVersion = "Xcode 3.2";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = F48D00E61E3B6EC000FE033E;
|
||||||
|
productRefGroup = F48D00F01E3B6EC000FE033E /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
F48D00EE1E3B6EC000FE033E /* LoopbackFS */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
F48D00ED1E3B6EC000FE033E /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
F48D00F81E3B6EC000FE033E /* MainMenu.xib in Resources */,
|
||||||
|
43E9539A2646E19C009CCB55 /* Assets.xcassets in Resources */,
|
||||||
|
F4D7409B1E65585B007D6E11 /* LICENSE.txt in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
F48D00EB1E3B6EC000FE033E /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
F48D00F31E3B6EC000FE033E /* AppDelegate.swift in Sources */,
|
||||||
|
F48D01091E3B7DA500FE033E /* NSError+POSIX.swift in Sources */,
|
||||||
|
F48D01071E3B74F900FE033E /* LoopbackFS.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXVariantGroup section */
|
||||||
|
F48D00F61E3B6EC000FE033E /* MainMenu.xib */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
F48D00F71E3B6EC000FE033E /* Base */,
|
||||||
|
);
|
||||||
|
name = MainMenu.xib;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
F48D00FA1E3B6EC000FE033E /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
OTHER_CODE_SIGN_FLAGS = "--timestamp";
|
||||||
|
SDKROOT = macosx;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
F48D00FB1E3B6EC000FE033E /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
OTHER_CODE_SIGN_FLAGS = "--timestamp";
|
||||||
|
SDKROOT = macosx;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
F48D00FD1E3B6EC000FE033E /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = LoopbackFS/LoopbackFS.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = /Library/Frameworks;
|
||||||
|
INFOPLIST_FILE = LoopbackFS/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "io.macfuse.demo.loopbackfs-swift";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "LoopbackFS/Bridging-Header.h";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
F48D00FE1E3B6EC000FE033E /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = LoopbackFS/LoopbackFS.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = /Library/Frameworks;
|
||||||
|
INFOPLIST_FILE = LoopbackFS/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "io.macfuse.demo.loopbackfs-swift";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "LoopbackFS/Bridging-Header.h";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
F48D00EA1E3B6EC000FE033E /* Build configuration list for PBXProject "LoopbackFS" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
F48D00FA1E3B6EC000FE033E /* Debug */,
|
||||||
|
F48D00FB1E3B6EC000FE033E /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
F48D00FC1E3B6EC000FE033E /* Build configuration list for PBXNativeTarget "LoopbackFS" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
F48D00FD1E3B6EC000FE033E /* Debug */,
|
||||||
|
F48D00FE1E3B6EC000FE033E /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = F48D00E71E3B6EC000FE033E /* Project object */;
|
||||||
|
}
|
||||||
7
LoopbackFS-Swift/LoopbackFS.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
LoopbackFS-Swift/LoopbackFS.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:LoopbackFS.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
//
|
||||||
|
// AppDelegate.swift
|
||||||
|
// LoopbackFS
|
||||||
|
//
|
||||||
|
// Created by Gunnar Herzog on 27/01/2017.
|
||||||
|
// Copyright © 2017 KF Interactive GmbH. All rights reserved.
|
||||||
|
// Copyright © 2019-2020 Benjamin Fleischer. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
let loopbackMountPath = "/Volumes/loop"
|
||||||
|
|
||||||
|
@NSApplicationMain
|
||||||
|
class AppDelegate: NSObject, NSApplicationDelegate {
|
||||||
|
|
||||||
|
@IBOutlet weak var window: NSWindow!
|
||||||
|
|
||||||
|
private var notificationObservers: [NSObjectProtocol] = []
|
||||||
|
private var rootPath: String!
|
||||||
|
private lazy var loopFileSystem: LoopbackFS = {
|
||||||
|
return LoopbackFS(rootPath: self.rootPath)
|
||||||
|
}()
|
||||||
|
|
||||||
|
private var userFileSystem: GMUserFileSystem?
|
||||||
|
|
||||||
|
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||||
|
let panel = NSOpenPanel()
|
||||||
|
panel.canChooseFiles = false
|
||||||
|
panel.canChooseDirectories = true
|
||||||
|
panel.allowsMultipleSelection = false
|
||||||
|
panel.directoryURL = URL(fileURLWithPath: "/tmp")
|
||||||
|
let returnValue = panel.runModal()
|
||||||
|
|
||||||
|
guard returnValue.rawValue != NSFileHandlingPanelCancelButton, let rootPath = panel.urls.first?.path else { exit(0) }
|
||||||
|
|
||||||
|
addNotifications()
|
||||||
|
|
||||||
|
self.rootPath = rootPath
|
||||||
|
|
||||||
|
var options: [String] = ["native_xattr", "volname=LoopbackFS"]
|
||||||
|
|
||||||
|
if let volumeIconPath = Bundle.main.path(forResource: "LoopbackFS", ofType: "icns") {
|
||||||
|
options.insert("volicon=\(volumeIconPath)", at: 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
userFileSystem = GMUserFileSystem(delegate: self.loopFileSystem, isThreadSafe: false)
|
||||||
|
|
||||||
|
// Do not use the 'native_xattr' mount-time option unless the underlying
|
||||||
|
// file system supports native extended attributes. Typically, the user
|
||||||
|
// would be mounting an HFS+ directory through LoopbackFS, so we do want
|
||||||
|
// this option in that case.
|
||||||
|
userFileSystem!.mount(atPath: loopbackMountPath, withOptions: options)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addNotifications() {
|
||||||
|
let mountObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name(kGMUserFileSystemDidMount), object: nil, queue: nil) { notification in
|
||||||
|
print("Got didMount notification.")
|
||||||
|
|
||||||
|
let parentPath = (loopbackMountPath as NSString).deletingLastPathComponent
|
||||||
|
NSWorkspace.shared.selectFile(loopbackMountPath, inFileViewerRootedAtPath: parentPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
let failedObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name(kGMUserFileSystemMountFailed), object: nil, queue: .main) { notification in
|
||||||
|
print("Got mountFailed notification.")
|
||||||
|
|
||||||
|
guard let userInfo = notification.userInfo, let error = userInfo[kGMUserFileSystemErrorKey] as? NSError else { return }
|
||||||
|
|
||||||
|
print("kGMUserFileSystem Error: \(error), userInfo=\(error.userInfo)")
|
||||||
|
let alert = NSAlert()
|
||||||
|
alert.messageText = "Mount Failed"
|
||||||
|
alert.informativeText = error.localizedDescription
|
||||||
|
alert.runModal()
|
||||||
|
|
||||||
|
NSApplication.shared.terminate(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
let unmountObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name(kGMUserFileSystemDidUnmount), object: nil, queue: nil) { notification in
|
||||||
|
print("Got didUnmount notification.")
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
NSApplication.shared.terminate(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.notificationObservers = [mountObserver, failedObserver, unmountObserver]
|
||||||
|
}
|
||||||
|
|
||||||
|
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
|
||||||
|
notificationObservers.forEach {
|
||||||
|
NotificationCenter.default.removeObserver($0)
|
||||||
|
}
|
||||||
|
notificationObservers.removeAll()
|
||||||
|
|
||||||
|
if let userFileSystem = userFileSystem {
|
||||||
|
userFileSystem.unmount()
|
||||||
|
}
|
||||||
|
return .terminateNow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "512x512"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "512x512"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,680 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="macosx"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17701"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
|
||||||
|
</connections>
|
||||||
|
</customObject>
|
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
|
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||||
|
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="LoopbackFS" customModuleProvider="target"/>
|
||||||
|
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||||
|
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
||||||
|
<items>
|
||||||
|
<menuItem title="LoopbackFS" id="1Xt-HY-uBw">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="LoopbackFS" systemMenu="apple" id="uQy-DD-JDr">
|
||||||
|
<items>
|
||||||
|
<menuItem title="About LoopbackFS" id="5kV-Vb-QxS">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
||||||
|
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
|
||||||
|
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
|
||||||
|
<menuItem title="Services" id="NMo-om-nkz">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
|
||||||
|
<menuItem title="Hide LoopbackFS" keyEquivalent="h" id="Olw-nP-bQN">
|
||||||
|
<connections>
|
||||||
|
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Show All" id="Kd2-mp-pUS">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
|
||||||
|
<menuItem title="Quit LoopbackFS" keyEquivalent="q" id="4sb-4s-VLi">
|
||||||
|
<connections>
|
||||||
|
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="File" id="dMs-cI-mzQ">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="File" id="bib-Uj-vzu">
|
||||||
|
<items>
|
||||||
|
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
|
||||||
|
<connections>
|
||||||
|
<action selector="newDocument:" target="-1" id="4Si-XN-c54"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
|
||||||
|
<connections>
|
||||||
|
<action selector="openDocument:" target="-1" id="bVn-NM-KNZ"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Open Recent" id="tXI-mr-wws">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Clear Menu" id="vNY-rz-j42">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="clearRecentDocuments:" target="-1" id="Daa-9d-B3U"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
|
||||||
|
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
|
||||||
|
<connections>
|
||||||
|
<action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
|
||||||
|
<connections>
|
||||||
|
<action selector="saveDocument:" target="-1" id="teZ-XB-qJY"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
|
||||||
|
<connections>
|
||||||
|
<action selector="saveDocumentAs:" target="-1" id="mDf-zr-I0C"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H">
|
||||||
|
<connections>
|
||||||
|
<action selector="revertDocumentToSaved:" target="-1" id="iJ3-Pv-kwq"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
|
||||||
|
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="runPageLayout:" target="-1" id="Din-rz-gC5"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
|
||||||
|
<connections>
|
||||||
|
<action selector="print:" target="-1" id="qaZ-4w-aoO"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Edit" id="5QF-Oa-p0T">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
|
||||||
|
<connections>
|
||||||
|
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
|
||||||
|
<connections>
|
||||||
|
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
|
||||||
|
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
|
||||||
|
<connections>
|
||||||
|
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
|
||||||
|
<connections>
|
||||||
|
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
|
||||||
|
<connections>
|
||||||
|
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Delete" id="pa3-QI-u2k">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
|
||||||
|
<connections>
|
||||||
|
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
|
||||||
|
<menuItem title="Find" id="4EN-yA-p0u">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Find" id="1b7-l0-nxx">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
|
||||||
|
<connections>
|
||||||
|
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
|
||||||
|
<connections>
|
||||||
|
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
|
||||||
|
<connections>
|
||||||
|
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
|
||||||
|
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Substitutions" id="9ic-FL-obx">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
|
||||||
|
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Smart Links" id="cwL-P1-jid">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Data Detectors" id="tRr-pd-1PS">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Transformations" id="2oI-Rn-ZJC">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Speech" id="xrE-MZ-jX0">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Format" id="jxT-CU-nIS">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Format" id="GEO-Iw-cKr">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Font" id="Gi5-1S-RQB">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq">
|
||||||
|
<connections>
|
||||||
|
<action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27">
|
||||||
|
<connections>
|
||||||
|
<action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq">
|
||||||
|
<connections>
|
||||||
|
<action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
|
||||||
|
<connections>
|
||||||
|
<action selector="underline:" target="-1" id="FYS-2b-JAY"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
|
||||||
|
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL">
|
||||||
|
<connections>
|
||||||
|
<action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST">
|
||||||
|
<connections>
|
||||||
|
<action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
|
||||||
|
<menuItem title="Kern" id="jBQ-r6-VK2">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Kern" id="tlD-Oa-oAM">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Use Default" id="GUa-eO-cwY">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="useStandardKerning:" target="-1" id="6dk-9l-Ckg"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Use None" id="cDB-IK-hbR">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="turnOffKerning:" target="-1" id="U8a-gz-Maa"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Tighten" id="46P-cB-AYj">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="tightenKerning:" target="-1" id="hr7-Nz-8ro"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Loosen" id="ogc-rX-tC1">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="loosenKerning:" target="-1" id="8i4-f9-FKE"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Ligatures" id="o6e-r0-MWq">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Use Default" id="agt-UL-0e3">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="useStandardLigatures:" target="-1" id="7uR-wd-Dx6"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Use None" id="J7y-lM-qPV">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="turnOffLigatures:" target="-1" id="iX2-gA-Ilz"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Use All" id="xQD-1f-W4t">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="useAllLigatures:" target="-1" id="KcB-kA-TuK"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Baseline" id="OaQ-X3-Vso">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Baseline" id="ijk-EB-dga">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Use Default" id="3Om-Ey-2VK">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="unscript:" target="-1" id="0vZ-95-Ywn"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Superscript" id="Rqc-34-cIF">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="superscript:" target="-1" id="3qV-fo-wpU"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Subscript" id="I0S-gh-46l">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="subscript:" target="-1" id="Q6W-4W-IGz"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Raise" id="2h7-ER-AoG">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="raiseBaseline:" target="-1" id="4sk-31-7Q9"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Lower" id="1tx-W0-xDw">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="lowerBaseline:" target="-1" id="OF1-bc-KW4"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
|
||||||
|
<menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
|
||||||
|
<connections>
|
||||||
|
<action selector="orderFrontColorPanel:" target="-1" id="mSX-Xz-DV3"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
|
||||||
|
<menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="copyFont:" target="-1" id="GJO-xA-L4q"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="pasteFont:" target="-1" id="JfD-CL-leO"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Text" id="Fal-I4-PZk">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Text" id="d9c-me-L2H">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
|
||||||
|
<connections>
|
||||||
|
<action selector="alignLeft:" target="-1" id="zUv-R1-uAa"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
|
||||||
|
<connections>
|
||||||
|
<action selector="alignCenter:" target="-1" id="spX-mk-kcS"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Justify" id="J5U-5w-g23">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="alignJustified:" target="-1" id="ljL-7U-jND"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
|
||||||
|
<connections>
|
||||||
|
<action selector="alignRight:" target="-1" id="r48-bG-YeY"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
|
||||||
|
<menuItem title="Writing Direction" id="H1b-Si-o9J">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem id="YGs-j5-SAR">
|
||||||
|
<string key="title"> Default</string>
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="makeBaseWritingDirectionNatural:" target="-1" id="qtV-5e-UBP"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem id="Lbh-J2-qVU">
|
||||||
|
<string key="title"> Left to Right</string>
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="makeBaseWritingDirectionLeftToRight:" target="-1" id="S0X-9S-QSf"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem id="jFq-tB-4Kx">
|
||||||
|
<string key="title"> Right to Left</string>
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="makeBaseWritingDirectionRightToLeft:" target="-1" id="5fk-qB-AqJ"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
|
||||||
|
<menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem id="Nop-cj-93Q">
|
||||||
|
<string key="title"> Default</string>
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="makeTextWritingDirectionNatural:" target="-1" id="lPI-Se-ZHp"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem id="BgM-ve-c93">
|
||||||
|
<string key="title"> Left to Right</string>
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="makeTextWritingDirectionLeftToRight:" target="-1" id="caW-Bv-w94"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem id="RB4-Sm-HuC">
|
||||||
|
<string key="title"> Right to Left</string>
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="makeTextWritingDirectionRightToLeft:" target="-1" id="EXD-6r-ZUu"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
|
||||||
|
<menuItem title="Show Ruler" id="vLm-3I-IUL">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleRuler:" target="-1" id="FOx-HJ-KwY"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="copyRuler:" target="-1" id="71i-fW-3W2"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="pasteRuler:" target="-1" id="cSh-wd-qM2"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="View" id="H8h-7b-M4v">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="View" id="HyV-fh-RgO">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleToolbarShown:" target="-1" id="BXY-wc-z0C"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="runToolbarCustomizationPalette:" target="-1" id="pQI-g3-MTW"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
|
||||||
|
<menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleSidebar:" target="-1" id="iwa-gc-5KM"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Window" id="aUF-d1-5bR">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
|
||||||
|
<connections>
|
||||||
|
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Zoom" id="R4o-n2-Eq4">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
|
||||||
|
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Help" id="wpr-3q-Mcd">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
|
||||||
|
<items>
|
||||||
|
<menuItem title="LoopbackFS Help" keyEquivalent="?" id="FKE-Sm-Kum">
|
||||||
|
<connections>
|
||||||
|
<action selector="showHelp:" target="-1" id="y7X-2Q-9no"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
<point key="canvasLocation" x="40" y="154"/>
|
||||||
|
</menu>
|
||||||
|
</objects>
|
||||||
|
</document>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
//
|
||||||
|
// Bridging-Header.h
|
||||||
|
// LoopbackFS
|
||||||
|
//
|
||||||
|
// Created by Gunnar Herzog on 27/01/2017.
|
||||||
|
// Copyright © 2017 KF Interactive GmbH. All rights reserved.
|
||||||
|
// Copyright © 2019 Benjamin Fleischer. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <macFUSE/macFUSE.h>
|
||||||
|
|
||||||
|
#import <sys/vnode.h>
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>Copyright © 2017 KF Interactive GmbH. All rights reserved.</string>
|
||||||
|
<key>NSMainNibFile</key>
|
||||||
|
<string>MainMenu</string>
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string>NSApplication</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.cs.disable-library-validation</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -0,0 +1,359 @@
|
||||||
|
//
|
||||||
|
// LoopbackFS.swift
|
||||||
|
// LoopbackFS
|
||||||
|
//
|
||||||
|
// Created by Gunnar Herzog on 27/01/2017.
|
||||||
|
// Copyright © 2017 KF Interactive GmbH. All rights reserved.
|
||||||
|
// Copyright © 2019-2020 Benjamin Fleischer. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
final class LoopbackFS: NSObject {
|
||||||
|
|
||||||
|
let rootPath: String
|
||||||
|
|
||||||
|
init(rootPath: String) {
|
||||||
|
self.rootPath = rootPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Moving an Item
|
||||||
|
|
||||||
|
override func moveItem(atPath source: String!, toPath destination: String!, options: GMUserFileSystemMoveOption) throws {
|
||||||
|
let sourcePath = (rootPath.appending(source) as NSString).utf8String!
|
||||||
|
let destinationPath = (rootPath.appending(destination) as NSString).utf8String!
|
||||||
|
|
||||||
|
var returnValue: Int32 = 0
|
||||||
|
if options.rawValue == 0 {
|
||||||
|
returnValue = rename(sourcePath, destinationPath)
|
||||||
|
} else {
|
||||||
|
if #available(OSX 10.12, *) {
|
||||||
|
var flags: UInt32 = 0;
|
||||||
|
if options.rawValue & GMUserFileSystemMoveOption.swap.rawValue != 0 {
|
||||||
|
flags |= UInt32(RENAME_SWAP);
|
||||||
|
}
|
||||||
|
if options.rawValue & GMUserFileSystemMoveOption.exclusive.rawValue != 0 {
|
||||||
|
flags |= UInt32(RENAME_EXCL);
|
||||||
|
}
|
||||||
|
returnValue = renamex_np(sourcePath, destinationPath, flags)
|
||||||
|
} else {
|
||||||
|
throw NSError(posixErrorCode: ENOTSUP);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if returnValue < 0 {
|
||||||
|
throw NSError(posixErrorCode: errno)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Removing an Item
|
||||||
|
|
||||||
|
override func removeDirectory(atPath path: String!) throws {
|
||||||
|
// We need to special-case directories here and use the bsd API since
|
||||||
|
// NSFileManager will happily do a recursive remove :-(
|
||||||
|
|
||||||
|
let originalPath = (rootPath.appending(path) as NSString).utf8String!
|
||||||
|
|
||||||
|
let returnValue = rmdir(originalPath)
|
||||||
|
if returnValue < 0 {
|
||||||
|
throw NSError(posixErrorCode: errno)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func removeItem(atPath path: String!) throws {
|
||||||
|
let originalPath = rootPath.appending(path)
|
||||||
|
|
||||||
|
return try FileManager.default.removeItem(atPath: originalPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Creating an Item
|
||||||
|
|
||||||
|
override func createDirectory(atPath path: String!, attributes: [AnyHashable : Any]! = [:]) throws {
|
||||||
|
guard let attributes = attributes as? [String: Any] else { throw NSError(posixErrorCode: EPERM) }
|
||||||
|
|
||||||
|
let originalPath = rootPath.appending(path)
|
||||||
|
|
||||||
|
try FileManager.default.createDirectory(atPath: originalPath, withIntermediateDirectories: false, attributes: convertToOptionalFileAttributeKeyDictionary(attributes))
|
||||||
|
}
|
||||||
|
|
||||||
|
override func createFile(atPath path: String!, attributes: [AnyHashable : Any]! = [:], flags: Int32, userData: AutoreleasingUnsafeMutablePointer<AnyObject?>!) throws {
|
||||||
|
|
||||||
|
guard let mode = attributes[FileAttributeKey.posixPermissions] as? mode_t else {
|
||||||
|
throw NSError(posixErrorCode: EPERM)
|
||||||
|
}
|
||||||
|
|
||||||
|
let originalPath = rootPath.appending(path)
|
||||||
|
|
||||||
|
let fileDescriptor = open((originalPath as NSString).utf8String!, flags, mode)
|
||||||
|
|
||||||
|
if fileDescriptor < 0 {
|
||||||
|
throw NSError(posixErrorCode: errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
userData.pointee = NSNumber(value: fileDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Linking an Item
|
||||||
|
|
||||||
|
override func linkItem(atPath path: String!, toPath otherPath: String!) throws {
|
||||||
|
let originalPath = (rootPath.appending(path) as NSString).utf8String!
|
||||||
|
let originalOtherPath = (rootPath.appending(otherPath) as NSString).utf8String!
|
||||||
|
|
||||||
|
// We use link rather than the NSFileManager equivalent because it will copy
|
||||||
|
// the file rather than hard link if part of the root path is a symlink.
|
||||||
|
if link(originalPath, originalOtherPath) < 0 {
|
||||||
|
throw NSError(posixErrorCode: errno)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Symbolic Links
|
||||||
|
|
||||||
|
override func createSymbolicLink(atPath path: String!, withDestinationPath otherPath: String!) throws {
|
||||||
|
let sourcePath = rootPath.appending(path)
|
||||||
|
try FileManager.default.createSymbolicLink(atPath: sourcePath, withDestinationPath: otherPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func destinationOfSymbolicLink(atPath path: String!) throws -> String {
|
||||||
|
let sourcePath = rootPath.appending(path)
|
||||||
|
return try FileManager.default.destinationOfSymbolicLink(atPath: sourcePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - File Contents
|
||||||
|
|
||||||
|
override func openFile(atPath path: String!, mode: Int32, userData: AutoreleasingUnsafeMutablePointer<AnyObject?>!) throws {
|
||||||
|
let originalPath = (rootPath.appending(path) as NSString).utf8String!
|
||||||
|
|
||||||
|
let fileDescriptor = open(originalPath, mode)
|
||||||
|
|
||||||
|
if fileDescriptor < 0 {
|
||||||
|
throw NSError(posixErrorCode: errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
userData.pointee = NSNumber(value: fileDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func releaseFile(atPath path: String!, userData: Any!) {
|
||||||
|
guard let num = userData as? NSNumber else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let fileDescriptor = num.int32Value
|
||||||
|
close(fileDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func readFile(atPath path: String!, userData: Any!, buffer: UnsafeMutablePointer<Int8>!, size: Int, offset: off_t, error: NSErrorPointer) -> Int32 {
|
||||||
|
guard let num = userData as? NSNumber else {
|
||||||
|
error?.pointee = NSError(posixErrorCode: EBADF)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
let fileDescriptor = num.int32Value
|
||||||
|
let returnValue = Int32(pread(fileDescriptor, buffer, size, offset))
|
||||||
|
|
||||||
|
if returnValue < 0 {
|
||||||
|
error?.pointee = NSError(posixErrorCode: errno)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return returnValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override func writeFile(atPath path: String!, userData: Any!, buffer: UnsafePointer<Int8>!, size: Int, offset: off_t, error: NSErrorPointer) -> Int32 {
|
||||||
|
guard let num = userData as? NSNumber else {
|
||||||
|
error?.pointee = NSError(posixErrorCode: EBADF)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
let fileDescriptor = num.int32Value
|
||||||
|
|
||||||
|
let returnValue = pwrite(fileDescriptor, buffer, size, offset)
|
||||||
|
if returnValue < 0 {
|
||||||
|
error?.pointee = NSError(posixErrorCode: errno)
|
||||||
|
}
|
||||||
|
return Int32(returnValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func preallocateFile(atPath path: String!, userData: Any!, options: Int32, offset: off_t, length: off_t) throws {
|
||||||
|
guard let num = userData as? NSNumber else {
|
||||||
|
throw NSError(posixErrorCode: EBADF)
|
||||||
|
}
|
||||||
|
|
||||||
|
let fileDescriptor = num.int32Value
|
||||||
|
|
||||||
|
var fstore = fstore_t()
|
||||||
|
if options & ALLOCATECONTIG == 1 {
|
||||||
|
fstore.fst_flags = UInt32(F_ALLOCATECONTIG)
|
||||||
|
}
|
||||||
|
if options & ALLOCATEALL == 1 {
|
||||||
|
fstore.fst_flags = fstore.fst_flags & UInt32(ALLOCATEALL)
|
||||||
|
}
|
||||||
|
if options & ALLOCATEFROMPEOF == 1 {
|
||||||
|
fstore.fst_posmode = F_PEOFPOSMODE
|
||||||
|
} else if options & ALLOCATEFROMVOL == 1 {
|
||||||
|
fstore.fst_posmode = F_VOLPOSMODE
|
||||||
|
}
|
||||||
|
fstore.fst_offset = offset
|
||||||
|
fstore.fst_length = length
|
||||||
|
if fcntl(fileDescriptor, F_PREALLOCATE, &fstore) == -1 {
|
||||||
|
throw NSError(posixErrorCode: errno)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func exchangeDataOfItem(atPath path1: String!, withItemAtPath path2: String!) throws {
|
||||||
|
let sourcePath = (rootPath.appending(path1) as NSString).utf8String!
|
||||||
|
let destinationPath = (rootPath.appending(path2) as NSString).utf8String!
|
||||||
|
|
||||||
|
let returnValue = exchangedata(sourcePath, destinationPath, 0)
|
||||||
|
if returnValue < 0 {
|
||||||
|
throw NSError(posixErrorCode: errno)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Directory Contents
|
||||||
|
|
||||||
|
override func contentsOfDirectory(atPath path: String!) throws -> [Any] {
|
||||||
|
let originalPath = rootPath.appending(path)
|
||||||
|
return try FileManager.default.contentsOfDirectory(atPath: originalPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Getting and Setting Attributes
|
||||||
|
|
||||||
|
override func attributesOfItem(atPath path: String!, userData: Any!) throws -> [AnyHashable : Any] {
|
||||||
|
let originalPath = rootPath.appending(path)
|
||||||
|
return try FileManager.default.attributesOfItem(atPath: originalPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func attributesOfFileSystem(forPath path: String!) throws -> [AnyHashable : Any] {
|
||||||
|
let originalPath = rootPath.appending(path)
|
||||||
|
|
||||||
|
var attributes = try FileManager.default.attributesOfFileSystem(forPath: originalPath)
|
||||||
|
attributes[FileAttributeKey(rawValue: kGMUserFileSystemVolumeSupportsExtendedDatesKey)] = true
|
||||||
|
|
||||||
|
let originalUrl = URL(fileURLWithPath: originalPath, isDirectory: true)
|
||||||
|
|
||||||
|
let volumeSupportsCaseSensitiveNames = try originalUrl.resourceValues(forKeys: [.volumeSupportsCaseSensitiveNamesKey]).volumeSupportsCaseSensitiveNames ?? true
|
||||||
|
attributes[FileAttributeKey(rawValue: kGMUserFileSystemVolumeSupportsCaseSensitiveNamesKey)] = volumeSupportsCaseSensitiveNames
|
||||||
|
|
||||||
|
attributes[FileAttributeKey(rawValue: kGMUserFileSystemVolumeSupportsSwapRenamingKey)] = true
|
||||||
|
attributes[FileAttributeKey(rawValue: kGMUserFileSystemVolumeSupportsExclusiveRenamingKey)] = true
|
||||||
|
|
||||||
|
attributes[FileAttributeKey(rawValue: kGMUserFileSystemVolumeSupportsSetVolumeNameKey)] = true
|
||||||
|
|
||||||
|
return attributes
|
||||||
|
}
|
||||||
|
|
||||||
|
override func setAttributes(_ attributes: [AnyHashable : Any]!, ofItemAtPath path: String!, userData: Any!) throws {
|
||||||
|
guard let attribs = attributes as? [FileAttributeKey: Any] else { throw NSError(posixErrorCode: EINVAL) }
|
||||||
|
|
||||||
|
let originalPath = rootPath.appending(path)
|
||||||
|
|
||||||
|
if let pathPointer = (originalPath as NSString).utf8String {
|
||||||
|
if let offset = attributes[FileAttributeKey.size.rawValue] as? Int64 {
|
||||||
|
let ret = truncate(pathPointer, offset)
|
||||||
|
if ret < 0 {
|
||||||
|
throw NSError(posixErrorCode: errno)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let flags = attributes[kGMUserFileSystemFileFlagsKey] as? Int32 {
|
||||||
|
let rc = chflags(pathPointer, UInt32(flags))
|
||||||
|
if rc < 0 {
|
||||||
|
throw NSError(posixErrorCode: errno)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try FileManager.default.setAttributes(attribs, ofItemAtPath: originalPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func setAttributes(_ attributes: [AnyHashable : Any]!, ofFileSystemAtPath path: String!) throws {
|
||||||
|
// Needed for kGMUserFileSystemVolumeSupportsSetVolumeNameKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Extended Attributes
|
||||||
|
|
||||||
|
public override func extendedAttributesOfItem(atPath path: Any!) throws -> [Any] {
|
||||||
|
guard let path = path as? String else {
|
||||||
|
throw NSError(posixErrorCode: ENODEV)
|
||||||
|
}
|
||||||
|
|
||||||
|
let originalUrl = URL(fileURLWithPath: rootPath.appending(path))
|
||||||
|
|
||||||
|
return try originalUrl.withUnsafeFileSystemRepresentation { fileSystemPath -> [String] in
|
||||||
|
let length = listxattr(fileSystemPath, nil, 0, 0)
|
||||||
|
guard length >= 0 else { throw NSError(posixErrorCode: errno) }
|
||||||
|
|
||||||
|
// Create buffer with required size:
|
||||||
|
var data = Data(count: length)
|
||||||
|
|
||||||
|
// Retrieve attribute list:
|
||||||
|
let count = data.count
|
||||||
|
let result = data.withUnsafeMutableBytes {
|
||||||
|
listxattr(fileSystemPath, $0.baseAddress?.assumingMemoryBound(to: Int8.self), count, XATTR_NOFOLLOW)
|
||||||
|
}
|
||||||
|
guard result >= 0 else { throw NSError(posixErrorCode: errno) }
|
||||||
|
|
||||||
|
// Extract attribute names:
|
||||||
|
let list = data.split(separator: 0).compactMap {
|
||||||
|
String(data: Data($0), encoding: .utf8)
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func value(ofExtendedAttribute name: String!, ofItemAtPath path: String!, position: off_t) throws -> Data {
|
||||||
|
let originalUrl = URL(fileURLWithPath: rootPath.appending(path))
|
||||||
|
|
||||||
|
return try originalUrl.withUnsafeFileSystemRepresentation { fileSystemPath -> Data in
|
||||||
|
|
||||||
|
// Determine attribute size:
|
||||||
|
let length = getxattr(fileSystemPath, name, nil, 0, UInt32(position), XATTR_NOFOLLOW)
|
||||||
|
guard length >= 0 else {
|
||||||
|
throw NSError(posixErrorCode: errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create buffer with required size:
|
||||||
|
var data = Data(count: length)
|
||||||
|
|
||||||
|
// Retrieve attribute:
|
||||||
|
let count = data.count
|
||||||
|
let result = data.withUnsafeMutableBytes {
|
||||||
|
getxattr(fileSystemPath, name, $0.baseAddress?.assumingMemoryBound(to: Int8.self), count, UInt32(position), XATTR_NOFOLLOW)
|
||||||
|
}
|
||||||
|
guard result >= 0 else {
|
||||||
|
throw NSError(posixErrorCode: errno)
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func setExtendedAttribute(_ name: String!, ofItemAtPath path: String!, value: Data!, position: off_t, options: Int32) throws {
|
||||||
|
let originalUrl = URL(fileURLWithPath: rootPath.appending(path))
|
||||||
|
|
||||||
|
try originalUrl.withUnsafeFileSystemRepresentation { fileSystemPath in
|
||||||
|
// Setting com.apple.FinderInfo happens in the kernel, so security related
|
||||||
|
// bits are set in the options. We need to explicitly remove them or the call
|
||||||
|
// to setxattr will fail.
|
||||||
|
// TODO: Why is this necessary?
|
||||||
|
let newOptions = options & ~(XATTR_NOSECURITY | XATTR_NODEFAULT)
|
||||||
|
|
||||||
|
let result = value.withUnsafeBytes {
|
||||||
|
setxattr(fileSystemPath, name, $0.baseAddress?.assumingMemoryBound(to: Int8.self), value.count, UInt32(position), newOptions | XATTR_NOFOLLOW)
|
||||||
|
}
|
||||||
|
guard result >= 0 else { throw NSError(posixErrorCode: errno) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func removeExtendedAttribute(_ name: String!, ofItemAtPath path: String!) throws {
|
||||||
|
let originalUrl = URL(fileURLWithPath: rootPath.appending(path))
|
||||||
|
|
||||||
|
try originalUrl.withUnsafeFileSystemRepresentation { fileSystemPath in
|
||||||
|
let result = removexattr(fileSystemPath, name, XATTR_NOFOLLOW)
|
||||||
|
guard result >= 0 else { throw NSError(posixErrorCode: errno) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function inserted by Swift 4.2 migrator.
|
||||||
|
fileprivate func convertToOptionalFileAttributeKeyDictionary(_ input: [String: Any]?) -> [FileAttributeKey: Any]? {
|
||||||
|
guard let input = input else { return nil }
|
||||||
|
return Dictionary(uniqueKeysWithValues: input.map { key, value in (FileAttributeKey(rawValue: key), value)})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
//
|
||||||
|
// NSError+POSIX.swift
|
||||||
|
// LoopbackFS
|
||||||
|
//
|
||||||
|
// Created by Gunnar Herzog on 27/01/2017.
|
||||||
|
// Copyright © 2017 KF Interactive GmbH. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension NSError {
|
||||||
|
convenience init(posixErrorCode err: Int32) {
|
||||||
|
self.init(domain: NSPOSIXErrorDomain, code: Int(err), userInfo: [NSLocalizedDescriptionKey: String(cString: strerror(err))])
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue