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