this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Added libsystem_copyfile

+6012 -1
+1
src/CMakeLists.txt
··· 57 57 add_subdirectory(libc) 58 58 add_subdirectory(libm) 59 59 add_subdirectory(libgcc) 60 + add_subdirectory(copyfile) 60 61 add_subdirectory(libinfo) 61 62 add_subdirectory(libmalloc) 62 63 add_subdirectory(libunwind)
+335
src/copyfile/APPLE_LICENSE
··· 1 + APPLE PUBLIC SOURCE LICENSE 2 + Version 2.0 - August 6, 2003 3 + 4 + Please read this License carefully before downloading this software. By 5 + downloading or using this software, you are agreeing to be bound by the terms 6 + of this License. If you do not or cannot agree to the terms of this License, 7 + please do not download or use the software. 8 + 9 + Apple Note: In January 2007, Apple changed its corporate name from "Apple 10 + Computer, Inc." to "Apple Inc." This change has been reflected below and 11 + copyright years updated, but no other changes have been made to the APSL 2.0. 12 + 13 + 1. General; Definitions. This License applies to any program or other 14 + work which Apple Inc. ("Apple") makes publicly available and which contains a 15 + notice placed by Apple identifying such program or work as "Original Code" and 16 + stating that it is subject to the terms of this Apple Public Source License 17 + version 2.0 ("License"). As used in this License: 18 + 19 + 1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is the 20 + grantor of rights, (i) claims of patents that are now or hereafter acquired, 21 + owned by or assigned to Apple and (ii) that cover subject matter contained in 22 + the Original Code, but only to the extent necessary to use, reproduce and/or 23 + distribute the Original Code without infringement; and (b) in the case where 24 + You are the grantor of rights, (i) claims of patents that are now or hereafter 25 + acquired, owned by or assigned to You and (ii) that cover subject matter in 26 + Your Modifications, taken alone or in combination with Original Code. 27 + 28 + 1.2 "Contributor" means any person or entity that creates or contributes to 29 + the creation of Modifications. 30 + 31 + 1.3 "Covered Code" means the Original Code, Modifications, the combination 32 + of Original Code and any Modifications, and/or any respective portions thereof. 33 + 34 + 1.4 "Externally Deploy" means: (a) to sublicense, distribute or otherwise 35 + make Covered Code available, directly or indirectly, to anyone other than You; 36 + and/or (b) to use Covered Code, alone or as part of a Larger Work, in any way 37 + to provide a service, including but not limited to delivery of content, through 38 + electronic communication with a client other than You. 39 + 40 + 1.5 "Larger Work" means a work which combines Covered Code or portions 41 + thereof with code not governed by the terms of this License. 42 + 43 + 1.6 "Modifications" mean any addition to, deletion from, and/or change to, 44 + the substance and/or structure of the Original Code, any previous 45 + Modifications, the combination of Original Code and any previous Modifications, 46 + and/or any respective portions thereof. When code is released as a series of 47 + files, a Modification is: (a) any addition to or deletion from the contents of 48 + a file containing Covered Code; and/or (b) any new file or other representation 49 + of computer program statements that contains any part of Covered Code. 50 + 51 + 1.7 "Original Code" means (a) the Source Code of a program or other work as 52 + originally made available by Apple under this License, including the Source 53 + Code of any updates or upgrades to such programs or works made available by 54 + Apple under this License, and that has been expressly identified by Apple as 55 + such in the header file(s) of such work; and (b) the object code compiled from 56 + such Source Code and originally made available by Apple under this License 57 + 58 + 1.8 "Source Code" means the human readable form of a program or other work 59 + that is suitable for making modifications to it, including all modules it 60 + contains, plus any associated interface definition files, scripts used to 61 + control compilation and installation of an executable (object code). 62 + 63 + 1.9 "You" or "Your" means an individual or a legal entity exercising rights 64 + under this License. For legal entities, "You" or "Your" includes any entity 65 + which controls, is controlled by, or is under common control with, You, where 66 + "control" means (a) the power, direct or indirect, to cause the direction or 67 + management of such entity, whether by contract or otherwise, or (b) ownership 68 + of fifty percent (50%) or more of the outstanding shares or beneficial 69 + ownership of such entity. 70 + 71 + 2. Permitted Uses; Conditions & Restrictions. Subject to the terms and 72 + conditions of this License, Apple hereby grants You, effective on the date You 73 + accept this License and download the Original Code, a world-wide, royalty-free, 74 + non-exclusive license, to the extent of Apple's Applicable Patent Rights and 75 + copyrights covering the Original Code, to do the following: 76 + 77 + 2.1 Unmodified Code. You may use, reproduce, display, perform, internally 78 + distribute within Your organization, and Externally Deploy verbatim, unmodified 79 + copies of the Original Code, for commercial or non-commercial purposes, 80 + provided that in each instance: 81 + 82 + (a) You must retain and reproduce in all copies of Original Code the 83 + copyright and other proprietary notices and disclaimers of Apple as they appear 84 + in the Original Code, and keep intact all notices in the Original Code that 85 + refer to this License; and 86 + 87 + (b) You must include a copy of this License with every copy of Source Code 88 + of Covered Code and documentation You distribute or Externally Deploy, and You 89 + may not offer or impose any terms on such Source Code that alter or restrict 90 + this License or the recipients' rights hereunder, except as permitted under 91 + Section 6. 92 + 93 + 2.2 Modified Code. You may modify Covered Code and use, reproduce, 94 + display, perform, internally distribute within Your organization, and 95 + Externally Deploy Your Modifications and Covered Code, for commercial or 96 + non-commercial purposes, provided that in each instance You also meet all of 97 + these conditions: 98 + 99 + (a) You must satisfy all the conditions of Section 2.1 with respect to the 100 + Source Code of the Covered Code; 101 + 102 + (b) You must duplicate, to the extent it does not already exist, the notice 103 + in Exhibit A in each file of the Source Code of all Your Modifications, and 104 + cause the modified files to carry prominent notices stating that You changed 105 + the files and the date of any change; and 106 + 107 + (c) If You Externally Deploy Your Modifications, You must make Source Code 108 + of all Your Externally Deployed Modifications either available to those to whom 109 + You have Externally Deployed Your Modifications, or publicly available. Source 110 + Code of Your Externally Deployed Modifications must be released under the terms 111 + set forth in this License, including the license grants set forth in Section 3 112 + below, for as long as you Externally Deploy the Covered Code or twelve (12) 113 + months from the date of initial External Deployment, whichever is longer. You 114 + should preferably distribute the Source Code of Your Externally Deployed 115 + Modifications electronically (e.g. download from a web site). 116 + 117 + 2.3 Distribution of Executable Versions. In addition, if You Externally 118 + Deploy Covered Code (Original Code and/or Modifications) in object code, 119 + executable form only, You must include a prominent notice, in the code itself 120 + as well as in related documentation, stating that Source Code of the Covered 121 + Code is available under the terms of this License with information on how and 122 + where to obtain such Source Code. 123 + 124 + 2.4 Third Party Rights. You expressly acknowledge and agree that although 125 + Apple and each Contributor grants the licenses to their respective portions of 126 + the Covered Code set forth herein, no assurances are provided by Apple or any 127 + Contributor that the Covered Code does not infringe the patent or other 128 + intellectual property rights of any other entity. Apple and each Contributor 129 + disclaim any liability to You for claims brought by any other entity based on 130 + infringement of intellectual property rights or otherwise. As a condition to 131 + exercising the rights and licenses granted hereunder, You hereby assume sole 132 + responsibility to secure any other intellectual property rights needed, if any. 133 + For example, if a third party patent license is required to allow You to 134 + distribute the Covered Code, it is Your responsibility to acquire that license 135 + before distributing the Covered Code. 136 + 137 + 3. Your Grants. In consideration of, and as a condition to, the licenses 138 + granted to You under this License, You hereby grant to any person or entity 139 + receiving or distributing Covered Code under this License a non-exclusive, 140 + royalty-free, perpetual, irrevocable license, under Your Applicable Patent 141 + Rights and other intellectual property rights (other than patent) owned or 142 + controlled by You, to use, reproduce, display, perform, modify, sublicense, 143 + distribute and Externally Deploy Your Modifications of the same scope and 144 + extent as Apple's licenses under Sections 2.1 and 2.2 above. 145 + 146 + 4. Larger Works. You may create a Larger Work by combining Covered Code 147 + with other code not governed by the terms of this License and distribute the 148 + Larger Work as a single product. In each such instance, You must make sure the 149 + requirements of this License are fulfilled for the Covered Code or any portion 150 + thereof. 151 + 152 + 5. Limitations on Patent License. Except as expressly stated in Section 153 + 2, no other patent rights, express or implied, are granted by Apple herein. 154 + Modifications and/or Larger Works may require additional patent licenses from 155 + Apple which Apple may grant in its sole discretion. 156 + 157 + 6. Additional Terms. You may choose to offer, and to charge a fee for, 158 + warranty, support, indemnity or liability obligations and/or other rights 159 + consistent with the scope of the license granted herein ("Additional Terms") to 160 + one or more recipients of Covered Code. However, You may do so only on Your own 161 + behalf and as Your sole responsibility, and not on behalf of Apple or any 162 + Contributor. You must obtain the recipient's agreement that any such Additional 163 + Terms are offered by You alone, and You hereby agree to indemnify, defend and 164 + hold Apple and every Contributor harmless for any liability incurred by or 165 + claims asserted against Apple or such Contributor by reason of any such 166 + Additional Terms. 167 + 168 + 7. Versions of the License. Apple may publish revised and/or new versions 169 + of this License from time to time. Each version will be given a distinguishing 170 + version number. Once Original Code has been published under a particular 171 + version of this License, You may continue to use it under the terms of that 172 + version. You may also choose to use such Original Code under the terms of any 173 + subsequent version of this License published by Apple. No one other than Apple 174 + has the right to modify the terms applicable to Covered Code created under this 175 + License. 176 + 177 + 8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in 178 + part pre-release, untested, or not fully tested works. The Covered Code may 179 + contain errors that could cause failures or loss of data, and may be incomplete 180 + or contain inaccuracies. You expressly acknowledge and agree that use of the 181 + Covered Code, or any portion thereof, is at Your sole and entire risk. THE 182 + COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF 183 + ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" 184 + FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM 185 + ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT 186 + LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF 187 + SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF 188 + QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. APPLE AND EACH 189 + CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE 190 + COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR 191 + REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR 192 + ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR 193 + WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE AUTHORIZED 194 + REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You acknowledge 195 + that the Covered Code is not intended for use in the operation of nuclear 196 + facilities, aircraft navigation, communication systems, or air traffic control 197 + machines in which case the failure of the Covered Code could lead to death, 198 + personal injury, or severe physical or environmental damage. 199 + 200 + 9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO 201 + EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, 202 + INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR 203 + YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER 204 + UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCTS 205 + LIABILITY OR OTHERWISE, EVEN IF APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF 206 + THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL 207 + PURPOSE OF ANY REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF 208 + LIABILITY OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT 209 + APPLY TO YOU. In no event shall Apple's total liability to You for all damages 210 + (other than as may be required by applicable law) under this License exceed the 211 + amount of fifty dollars ($50.00). 212 + 213 + 10. Trademarks. This License does not grant any rights to use the 214 + trademarks or trade names "Apple", "Mac", "Mac OS", "QuickTime", "QuickTime 215 + Streaming Server" or any other trademarks, service marks, logos or trade names 216 + belonging to Apple (collectively "Apple Marks") or to any trademark, service 217 + mark, logo or trade name belonging to any Contributor. You agree not to use 218 + any Apple Marks in or as part of the name of products derived from the Original 219 + Code or to endorse or promote products derived from the Original Code other 220 + than as expressly permitted by and in strict compliance at all times with 221 + Apple's third party trademark usage guidelines which are posted at 222 + http://www.apple.com/legal/guidelinesfor3rdparties.html. 223 + 224 + 11. Ownership. Subject to the licenses granted under this License, each 225 + Contributor retains all rights, title and interest in and to any Modifications 226 + made by such Contributor. Apple retains all rights, title and interest in and 227 + to the Original Code and any Modifications made by or on behalf of Apple 228 + ("Apple Modifications"), and such Apple Modifications will not be automatically 229 + subject to this License. Apple may, at its sole discretion, choose to license 230 + such Apple Modifications under this License, or on different terms from those 231 + contained in this License or may choose not to license them at all. 232 + 233 + 12. Termination. 234 + 235 + 12.1 Termination. This License and the rights granted hereunder will 236 + terminate: 237 + 238 + (a) automatically without notice from Apple if You fail to comply with any 239 + term(s) of this License and fail to cure such breach within 30 days of becoming 240 + aware of such breach; 241 + (b) immediately in the event of the circumstances described in Section 242 + 13.5(b); or 243 + (c) automatically without notice from Apple if You, at any time during the 244 + term of this License, commence an action for patent infringement against Apple; 245 + provided that Apple did not first commence an action for patent infringement 246 + against You in that instance. 247 + 248 + 12.2 Effect of Termination. Upon termination, You agree to immediately stop 249 + any further use, reproduction, modification, sublicensing and distribution of 250 + the Covered Code. All sublicenses to the Covered Code which have been properly 251 + granted prior to termination shall survive any termination of this License. 252 + Provisions which, by their nature, should remain in effect beyond the 253 + termination of this License shall survive, including but not limited to 254 + Sections 3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other 255 + for compensation, indemnity or damages of any sort solely as a result of 256 + terminating this License in accordance with its terms, and termination of this 257 + License will be without prejudice to any other right or remedy of any party. 258 + 259 + 13. Miscellaneous. 260 + 261 + 13.1 Government End Users. The Covered Code is a "commercial item" as 262 + defined in FAR 2.101. Government software and technical data rights in the 263 + Covered Code include only those rights customarily provided to the public as 264 + defined in this License. This customary commercial license in technical data 265 + and software is provided in accordance with FAR 12.211 (Technical Data) and 266 + 12.212 (Computer Software) and, for Department of Defense purchases, DFAR 267 + 252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3 (Rights in 268 + Commercial Computer Software or Computer Software Documentation). Accordingly, 269 + all U.S. Government End Users acquire Covered Code with only those rights set 270 + forth herein. 271 + 272 + 13.2 Relationship of Parties. This License will not be construed as 273 + creating an agency, partnership, joint venture or any other form of legal 274 + association between or among You, Apple or any Contributor, and You will not 275 + represent to the contrary, whether expressly, by implication, appearance or 276 + otherwise. 277 + 278 + 13.3 Independent Development. Nothing in this License will impair Apple's 279 + right to acquire, license, develop, have others develop for it, market and/or 280 + distribute technology or products that perform the same or similar functions 281 + as, or otherwise compete with, Modifications, Larger Works, technology or 282 + products that You may develop, produce, market or distribute. 283 + 284 + 13.4 Waiver; Construction. Failure by Apple or any Contributor to enforce 285 + any provision of this License will not be deemed a waiver of future enforcement 286 + of that or any other provision. Any law or regulation which provides that the 287 + language of a contract shall be construed against the drafter will not apply to 288 + this License. 289 + 290 + 13.5 Severability. (a) If for any reason a court of competent jurisdiction 291 + finds any provision of this License, or portion thereof, to be unenforceable, 292 + that provision of the License will be enforced to the maximum extent 293 + permissible so as to effect the economic benefits and intent of the parties, 294 + and the remainder of this License will continue in full force and effect. (b) 295 + Notwithstanding the foregoing, if applicable law prohibits or restricts You 296 + from fully and/or specifically complying with Sections 2 and/or 3 or prevents 297 + the enforceability of either of those Sections, this License will immediately 298 + terminate and You must immediately discontinue any use of the Covered Code and 299 + destroy all copies of it that are in your possession or control. 300 + 301 + 13.6 Dispute Resolution. Any litigation or other dispute resolution between 302 + You and Apple relating to this License shall take place in the Northern 303 + District of California, and You and Apple hereby consent to the personal 304 + jurisdiction of, and venue in, the state and federal courts within that 305 + District with respect to this License. The application of the United Nations 306 + Convention on Contracts for the International Sale of Goods is expressly 307 + excluded. 308 + 309 + 13.7 Entire Agreement; Governing Law. This License constitutes the entire 310 + agreement between the parties with respect to the subject matter hereof. This 311 + License shall be governed by the laws of the United States and the State of 312 + California, except that body of California law concerning conflicts of law. 313 + 314 + Where You are located in the province of Quebec, Canada, the following clause 315 + applies: The parties hereby confirm that they have requested that this License 316 + and all related documents be drafted in English. Les parties ont exigé que le 317 + présent contrat et tous les documents connexes soient rédigés en anglais. 318 + 319 + EXHIBIT A. 320 + 321 + "Portions Copyright (c) 1999-2007 Apple Inc. All Rights Reserved. 322 + 323 + This file contains Original Code and/or Modifications of Original Code as 324 + defined in and that are subject to the Apple Public Source License Version 2.0 325 + (the 'License'). You may not use this file except in compliance with the 326 + License. Please obtain a copy of the License at 327 + http://www.opensource.apple.com/apsl/ and read it before using this file. 328 + 329 + The Original Code and all software distributed under the License are 330 + distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 331 + OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 332 + LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 333 + PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 334 + specific language governing rights and limitations under the License." 335 +
+29
src/copyfile/CMakeLists.txt
··· 1 + project(copyfile) 2 + 3 + cmake_minimum_required(VERSION 2.4.0) 4 + 5 + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdinc -fblocks") 6 + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -nostdlib -Wl,--version-script=${DARLING_TOP_DIRECTORY}/darwin.map") 7 + 8 + include_directories(${DARLING_TOP_DIRECTORY}/platform-include) 9 + include_directories(${DARLING_TOP_DIRECTORY}/src/libinfo/membership.subproj/) 10 + include_directories(${DARLING_TOP_DIRECTORY}/src/external/libdispatch) 11 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 12 + 13 + add_definitions(-DTARGET_OS_MAC=1) 14 + add_definitions(-DHAVE_STDINT_H=1) 15 + add_definitions(-D__APPLE__ -D__DYNAMIC__) 16 + 17 + set(copyfile_sources 18 + copyfile.c 19 + # xattr_flags.c # Doesn't build yet (XPC) 20 + ) 21 + 22 + SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib${SUFFIX}/darling") 23 + SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) 24 + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 25 + 26 + add_library(system_copyfile SHARED ${copyfile_sources}) 27 + target_link_libraries(system_copyfile system_kernel system_c) 28 + 29 + install(TARGETS system_copyfile DESTINATION lib${SUFFIX}/darling)
+1
src/copyfile/Kernel
··· 1 + ../../kernel-include/
+588
src/copyfile/copyfile.3
··· 1 + .\" 2 + .\" Copyright (c) 2002 Apple Computer, Inc. All rights reserved. 3 + .\" 4 + .Dd April 27, 2006 5 + .Dt COPYFILE 3 6 + .Os 7 + .Sh NAME 8 + .Nm copyfile , fcopyfile , 9 + .Nm copyfile_state_alloc , copyfile_state_free , 10 + .Nm copyfile_state_get , copyfile_state_set 11 + .Nd copy a file 12 + .Sh LIBRARY 13 + .Lb libc 14 + .Sh SYNOPSIS 15 + .In copyfile.h 16 + .Ft int 17 + .Fn copyfile "const char *from" "const char *to" "copyfile_state_t state" "copyfile_flags_t flags" 18 + .Ft int 19 + .Fn fcopyfile "int from" "int to" "copyfile_state_t state" "copyfile_flags_t flags" 20 + .Ft copyfile_state_t 21 + .Fn copyfile_state_alloc "void" 22 + .Ft int 23 + .Fn copyfile_state_free "copyfile_state_t state" 24 + .Ft int 25 + .Fn copyfile_state_get "copyfile_state_t state" "uint32_t flag" "void * dst" 26 + .Ft int 27 + .Fn copyfile_state_set "copyfile_state_t state" "uint32_t flag" "const void * src" 28 + .Ft typedef int 29 + .Fn (*copyfile_callback_t) "int what" "int stage" "copyfile_state_t state" "const char * src" "const char * dst" "void * ctx" 30 + .Sh DESCRIPTION 31 + These functions are used to copy a file's data and/or metadata. (Metadata 32 + consists of permissions, extended attributes, access control lists, and so 33 + forth.) 34 + .Pp 35 + The 36 + .Fn copyfile_state_alloc 37 + function initializes a 38 + .Vt copyfile_state_t 39 + object (which is an opaque data type). 40 + This object can be passed to 41 + .Fn copyfile 42 + and 43 + .Fn fcopyfile ; 44 + .Fn copyfile_state_get 45 + and 46 + .Fn copyfile_state_set 47 + can be used to manipulate the state (see below). 48 + The 49 + .Fn copyfile_state_free 50 + function is used to deallocate the object and its contents. 51 + .Pp 52 + The 53 + .Fn copyfile 54 + function can copy the named 55 + .Va from 56 + file to the named 57 + .Va to 58 + file; the 59 + .Fn fcopyfile 60 + function does the same, but using the file descriptors of already-opened 61 + files. 62 + If the 63 + .Va state 64 + parameter is the return value from 65 + .Fn copyfile_state_alloc , 66 + then 67 + .Fn copyfile 68 + and 69 + .Fn fcopyfile 70 + will use the information from the state object; if it is 71 + .Dv NULL , 72 + then both functions will work normally, but less control will be available to the caller. 73 + The 74 + .Va flags 75 + parameter controls which contents are copied: 76 + .Bl -tag -width COPYFILE_XATTR 77 + .It Dv COPYFILE_ACL 78 + Copy the source file's access control lists. 79 + .It Dv COPYFILE_STAT 80 + Copy the source file's POSIX information (mode, modification time, etc.). 81 + .It Dv COPYFILE_XATTR 82 + Copy the source file's extended attributes. 83 + .It Dv COPYFILE_DATA 84 + Copy the source file's data. 85 + .El 86 + .Pp 87 + These values may be or'd together; several convenience macros are provided: 88 + .Bl -tag -width COPYFILE_SECURITY 89 + .It Dv COPYFILE_SECURITY 90 + Copy the source file's POSIX and ACL information; equivalent to 91 + .Dv (COPYFILE_STAT|COPYFILE_ACL) . 92 + .It Dv COPYFILE_METADATA 93 + Copy the metadata; equivalent to 94 + .Dv (COPYFILE_SECURITY|COPYFILE_XATTR) . 95 + .It Dv COPYFILE_ALL 96 + Copy the entire file; equivalent to 97 + .Dv (COPYFILE_METADATA|COPYFILE_DATA) . 98 + .El 99 + .Pp 100 + The 101 + .Fn copyfile 102 + and 103 + .Fn fcopyfile 104 + functions can also have their behavior modified by the following flags: 105 + .Bl -tag -width COPYFILE_NOFOLLOW_SRC 106 + .It Dv COPYFILE_RECURSIVE 107 + Causes 108 + .Fn copyfile 109 + to recursively copy a hierarchy. 110 + This flag is not used by 111 + .Fn fcopyfile ; 112 + see below for more information. 113 + .It Dv COPYFILE_CHECK 114 + Return a bitmask (corresponding to the 115 + .Va flags 116 + argument) indicating which contents would be copied; no data are actually 117 + copied. (E.g., if 118 + .Va flags 119 + was set to 120 + .Dv COPYFILE_CHECK|COPYFILE_METADATA , 121 + and the 122 + .Va from 123 + file had extended attributes but no ACLs, the return value would be 124 + .Dv COPYFILE_XATTR .) 125 + .It Dv COPYFILE_PACK 126 + Serialize the 127 + .Va from 128 + file. The 129 + .Va to 130 + file is an AppleDouble-format file. 131 + .It Dv COPYFILE_UNPACK 132 + Unserialize the 133 + .Va from 134 + file. The 135 + .Va from 136 + file is an AppleDouble-format file; the 137 + .Va to 138 + file will have the extended attributes, ACLs, resource fork, and 139 + FinderInfo data from the 140 + .Va to 141 + file, regardless of the 142 + .Va flags 143 + argument passed in. 144 + .It Dv COPYFILE_EXCL 145 + Fail if the 146 + .Va to 147 + file already exists. (This is only applicable for the 148 + .Fn copyfile 149 + function.) 150 + .It Dv COPYFILE_NOFOLLOW_SRC 151 + Do not follow the 152 + .Va from 153 + file, if it is a symbolic link. (This is only applicable for the 154 + .Fn copyfile 155 + function.) 156 + .It Dv COPYFILE_NOFOLLOW_DST 157 + Do not follow the 158 + .Va to 159 + file, if it is a symbolic link. (This is only applicable for the 160 + .Fn copyfile 161 + function.) 162 + .It Dv COPYFILE_MOVE 163 + Unlink (using 164 + .Xr remove 3 ) 165 + the 166 + .Fa from 167 + file. (This is only applicable for the 168 + .Fn copyfile 169 + function.) No error is returned if 170 + .Xr remove 3 171 + fails. Note that 172 + .Xr remove 3 173 + removes a symbolic link itself, not the 174 + target of the link. 175 + .It Dv COPYFILE_UNLINK 176 + Unlink the 177 + .Va to 178 + file before starting. (This is only applicable for the 179 + .Fn copyfile 180 + function.) 181 + .It Dv COPYFILE_NOFOLLOW 182 + This is a convenience macro, equivalent to 183 + .Dv (COPYFILE_NOFOLLOW_DST|COPYFILE_NOFOLLOW_SRC) . 184 + .El 185 + .Pp 186 + The 187 + .Fn copyfile_state_get 188 + and 189 + .Fn copyfile_state_set 190 + functions can be used to manipulate the 191 + .Ft copyfile_state_t 192 + object returned by 193 + .Fn copyfile_state_alloc . 194 + In both functions, the 195 + .Va dst 196 + parameter's type depends on the 197 + .Va flag 198 + parameter that is passed in. 199 + .Bl -tag -width COPYFILE_STATE_DST_FILENAME 200 + .It Dv COPYFILE_STATE_SRC_FD 201 + .It Dv COPYFILE_STATE_DST_FD 202 + Get or set the file descriptor associated with the source (or destination) 203 + file. 204 + If this has not been initialized yet, the value will be -2. 205 + The 206 + .Va dst 207 + (for 208 + .Fn copyfile_state_get ) 209 + and 210 + .Va src 211 + (for 212 + .Fn copyfile_state_set ) 213 + parameters are pointers to 214 + .Vt int . 215 + .It Dv COPYFILE_STATE_SRC_FILENAME 216 + .It Dv COPYFILE_STATE_DST_FILENAME 217 + Get or set the filename associated with the source (or destination) 218 + file. If it has not been initialized yet, the value will be 219 + .Dv NULL . 220 + For 221 + .Fn copyfile_state_set , 222 + the 223 + .Va src 224 + parameter is a pointer to a C string 225 + (i.e., 226 + .Vt char* ); 227 + .Fn copyfile_state_set 228 + makes a private copy of this string. 229 + For 230 + .Fn copyfile_state_get 231 + function, the 232 + .Va dst 233 + parameter is a pointer to a pointer to a C string 234 + (i.e., 235 + .Vt char** ); 236 + the returned value is a pointer to the 237 + .Va state 's 238 + copy, and must not be modified or released. 239 + .It Dv COPYFILE_STATE_STATUS_CB 240 + Get or set the callback status function (currently 241 + only used for recursive copies; see below for details). 242 + The 243 + .Va src 244 + parameter is a pointer to a function of type 245 + .Vt copyfile_callback_t 246 + (see above). 247 + .It Dv COPYFILE_STATE_STATUS_CTX 248 + Get or set the context parameter for the status 249 + call-back function (see below for details). 250 + The 251 + .Va src 252 + parameter is a 253 + .Vt void\ * . 254 + .It Dv COPYFILE_STATE_QUARANTINE 255 + Get or set the quarantine information with the source file. 256 + The 257 + .Va src 258 + parameter is a pointer to an opaque 259 + object (type 260 + .Vt void\ * 261 + ). 262 + .It Dv COPYFILE_STATE_COPIED 263 + Get the number of data bytes copied so far. 264 + (Only valid for 265 + .Fn copyfile_state_get ; 266 + see below for more details about callbacks.) 267 + The 268 + .Va dst 269 + parameter is a pointer to 270 + .Vt off_t 271 + (type 272 + .Vt off_t\ * ). 273 + .It Dv COPYFILE_STATE_XATTRNAME 274 + Get the name of the extended attribute during a callback 275 + for 276 + .Dv COPYFILE_COPY_XATTR 277 + (see below for details). This field cannot be set, 278 + and may be 279 + .Dv NULL . 280 + .El 281 + .Sh Recursive Copies 282 + When given the 283 + .Dv COPYFILE_RECURSIVE 284 + flag, 285 + .Fn copyfile 286 + (but not 287 + .Fn fcopyfile ) 288 + will use the 289 + .Xr fts 3 290 + functions to recursively descend into the source file-system object. 291 + It then calls 292 + .Fn copyfile 293 + on each of the entries it finds that way. 294 + If a call-back function is given (using 295 + .Fn copyfile_state_set 296 + and 297 + .Dv COPYFILE_STATE_STATUS_CB ), 298 + the call-back function will be called four times for each directory 299 + object, and twice for all other objects. (Each directory will 300 + be examined twice, once on entry -- before copying each of the 301 + objects contained in the directory -- and once on exit -- after 302 + copying each object contained in the directory, in order to perform 303 + some final cleanup.) 304 + .Pp 305 + The call-back function will have one of the following values 306 + as the first argument, indicating what is being copied: 307 + .Bl -tag -width COPYFILE_RECURSE_DIR_CLEANUP 308 + .It Dv COPYFILE_RECURSE_FILE 309 + The object being copied is a file (or, rather, 310 + something other than a directory). 311 + .It Dv COPYFILE_RECURSE_DIR 312 + The object being copied is a directory, and is being 313 + entered. (That is, none of the filesystem objects contained 314 + within the directory have been copied yet.) 315 + .It Dv COPYFILE_RECURSE_DIR_CLEANUP 316 + The object being copied is a directory, and all of the 317 + objects contained have been copied. At this stage, the destination directory 318 + being copied will have any extra permissions that were added to 319 + allow the copying will be removed. 320 + .It Dv COPYFILE_RECURSE_ERROR 321 + There was an error in processing an element of the source hierarchy; 322 + this happens when 323 + .Xr fts 3 324 + returns an error or unknown file type. 325 + (Currently, the second argument to the call-back function will always 326 + be 327 + .Dv COPYFILE_ERR 328 + in this case.) 329 + .El 330 + .Pp 331 + The second argument to the call-back function will indicate 332 + the stage of the copy, and will be one of the following values: 333 + .Bl -tag -width COPYFILE_FINISH 334 + .It Dv COPYFILE_START 335 + Before copying has begun. The third 336 + parameter will be a newly-created 337 + .Vt copyfile_state_t 338 + object with the call-back function and context pre-loaded. 339 + .It Dv COPYFILE_FINISH 340 + After copying has successfully finished. 341 + .It Dv COPYFILE_ERR 342 + Indicates an error has happened at some stage. If the 343 + first argument to the call-back function is 344 + .Dv COPYFILE_RECURSE_ERROR , 345 + then an error occurred while processing the source hierarchy; 346 + otherwise, it will indicate what type of object was being copied, 347 + and 348 + .Dv errno 349 + will be set to indicate the error. 350 + .El 351 + .Pp 352 + The fourth and fifth 353 + parameters are the source and destination paths that 354 + are to be copied (or have been copied, or failed to copy, depending on 355 + the second argument). 356 + .Pp 357 + The last argument to the call-back function will be the value 358 + set by 359 + .Dv COPYFILE_STATE_STATUS_CTX , 360 + if any. 361 + .Pp 362 + The call-back function is required to return one of the following 363 + values: 364 + .Bl -tag -width COPYFILE_CONTINUE 365 + .It Dv COPYFILE_CONTINUE 366 + The copy will continue as expected. 367 + .It Dv COPYFILE_SKIP 368 + This object will be skipped, and the next object will 369 + be processed. (Note that, when entering a directory. 370 + returning 371 + .Dv COPYFILE_SKIP 372 + from the call-back function will prevent the contents 373 + of the directory from being copied.) 374 + .It Dv COPYFILE_QUIT 375 + The entire copy is aborted at this stage. Any filesystem 376 + objects created up to this point will remain. 377 + .Fn copyfile 378 + will return -1, but 379 + .Dv errno 380 + will be unmodified. 381 + .El 382 + .Pp 383 + The call-back function must always return one of the values listed 384 + above; if not, the results are undefined. 385 + .Pp 386 + The call-back function will be called twice for each object 387 + (and an additional two times for directory cleanup); the first 388 + call will have a 389 + .Ar stage 390 + parameter of 391 + .Dv COPYFILE_START ; 392 + the second time, that value will be either 393 + .Dv COPYFILE_FINISH 394 + or 395 + .Dv COPYFILE_ERR 396 + to indicate a successful completion, or an error during 397 + processing. 398 + In the event of an error, the 399 + .Dv errno 400 + value will be set appropriately. 401 + .Pp 402 + The 403 + .Dv COPYFILE_PACK , 404 + .Dv COPYFILE_UNPACK , 405 + .Dv COPYFILE_MOVE , 406 + and 407 + .Dv COPYFILE_UNLINK 408 + flags are not used during a recursive copy, and will result 409 + in an error being returned. 410 + .Sh Progress Callback 411 + In addition to the recursive callbacks described above, 412 + .Fn copyfile 413 + and 414 + .Fn fcopyfile 415 + will also use a callback to report data (e.g., 416 + .Dv COPYFILE_DATA ) 417 + progress. If given, the callback will be invoked on each 418 + .Xr write 2 419 + call. The first argument to the callback function will be 420 + .Dv COPYFILE_COPY_DATA . 421 + The second argument will either be 422 + .Dv COPYFILE_PROGRESS 423 + (indicating that the write was successful), or 424 + .Dv COPYFILE_ERR 425 + (indicating that there was an error of some sort). 426 + .Pp 427 + The amount of data bytes copied so far can be retrieved using 428 + .Fn copyfile_state_get , 429 + with the 430 + .Dv COPYFILE_STATE_COPIED 431 + requestor (the argument type is a pointer to 432 + .Vt off_t ). 433 + .Pp 434 + When copying extended attributes, the first argument to the 435 + callback function will be 436 + .Dv COPYFILE_COPY_XATTR . 437 + The other arguments will be as described for 438 + .Dv COPYFILE_COPY_DATA ; 439 + the name of the extended attribute being copied may be 440 + retrieved using 441 + .Fn copyfile_state_get 442 + and the parameter 443 + .Dv COPYFILE_STATE_XATTRNAME . 444 + When using 445 + .Dv COPYFILE_PACK , 446 + the callback may be called with 447 + .Dv COPYFILE_START 448 + for each of the extended attributes first, followed by 449 + .Dv COPYFILE_PROGRESS 450 + before getting and packing the data for each 451 + individual attribute, and then 452 + .Dv COPYFILE_FINISH 453 + when finished with each individual attribute. 454 + (That is, 455 + .Dv COPYFILE_START 456 + may be called for all of the extended attributes, before 457 + the first callback with 458 + .Dv COPYFILE_PROGRESS 459 + is invoked.) Any attribute skipped by returning 460 + .Dv COPYFILE_SKIP 461 + from the 462 + .Dv COPYFILE_START 463 + callback will not be placed into the packed output file. 464 + .Pp 465 + The return value for the data callback must be one of 466 + .Bl -tag -width COPYFILE_CONTINUE 467 + .It Dv COPYFILE_CONTINUE 468 + The copy will continue as expected. 469 + (In the case of error, it will attempt to write the data again.) 470 + .It Dv COPYFILE_SKIP 471 + The data copy will be aborted, but without error. 472 + .It Dv COPYFILE_QUIT 473 + The data copy will be aborted; in the case of 474 + .Dv COPYFILE_PROGRESS , 475 + .Dv errno 476 + will be set to 477 + .Dv ECANCELED . 478 + .El 479 + .Pp 480 + While the 481 + .Va src 482 + and 483 + .Va dst 484 + parameters will be passed in, they may be 485 + .Dv NULL 486 + in the case of 487 + .Fn fcopyfile . 488 + .Sh RETURN VALUES 489 + Except when given the 490 + .Dv COPYFILE_CHECK 491 + flag, 492 + .Fn copyfile 493 + and 494 + .Fn fcopyfile 495 + return less than 0 on error, and 0 on success. 496 + All of the other functions return 0 on success, and less than 0 497 + on error. 498 + .Sh WARNING 499 + Both 500 + .Fn copyfile 501 + and 502 + .Fn fcopyfile 503 + can copy symbolic links; there is a gap between when the source 504 + link is examined and the actual copy is started, and this can 505 + be a potential security risk, especially if the process has 506 + elevated privileges. 507 + .Pp 508 + When performing a recursive copy, if the source hierarchy 509 + changes while the copy is occurring, the results are undefined. 510 + .Pp 511 + .Fn fcopyfile 512 + does not reset the seek position for either source or destination. 513 + This can result in the destination file being a different size 514 + than the source file. 515 + .Sh ERRORS 516 + .Fn copyfile 517 + and 518 + .Fn fcopyfile 519 + will fail if: 520 + .Bl -tag -width Er 521 + .It Bq Er EINVAL 522 + An invalid flag was passed in with 523 + .Dv COPYFILE_RECURSIVE . 524 + .It Bq Er EINVAL 525 + The 526 + .Va from 527 + or 528 + .Va to 529 + parameter to 530 + .Fn copyfile 531 + was a 532 + .Dv NULL 533 + pointer. 534 + .It Bq Er EINVAL 535 + The 536 + .Va from 537 + or 538 + .Va to 539 + parameter to 540 + .Fn copyfile 541 + was a negative number. 542 + .It Bq Er ENOMEM 543 + A memory allocation failed. 544 + .It Bq Er ENOTSUP 545 + The source file was not a directory, symbolic link, or regular file. 546 + .It Bq Er ECANCELED 547 + The copy was cancelled by callback. 548 + .El 549 + In addition, both functions may set 550 + .Dv errno 551 + via an underlying library or system call. 552 + .Sh EXAMPLES 553 + .Bd -literal -offset indent 554 + /* Initialize a state variable */ 555 + copyfile_state_t s; 556 + s = copyfile_state_alloc(); 557 + /* Copy the data and extended attributes of one file to another */ 558 + copyfile("/tmp/f1", "/tmp/f2", s, COPYFILE_DATA | COPYFILE_XATTR); 559 + /* Convert a file to an AppleDouble file for serialization */ 560 + copyfile("/tmp/f2", "/tmp/tmpfile", NULL, COPYFILE_ALL | COPYFILE_PACK); 561 + /* Release the state variable */ 562 + copyfile_state_free(s); 563 + /* A more complex way to call copyfile() */ 564 + s = copyfile_state_alloc(); 565 + copyfile_state_set(s, COPYFILE_STATE_SRC_FILENAME, "/tmp/foo"); 566 + /* One of src or dst must be set... rest can come from the state */ 567 + copyfile(NULL, "/tmp/bar", s, COPYFILE_ALL); 568 + /* Now copy the same source file to another destination file */ 569 + copyfile(NULL, "/tmp/car", s, COPYFILE_ALL); 570 + copyfile_state_free(s); 571 + /* Remove extended attributes from a file */ 572 + copyfile("/dev/null", "/tmp/bar", NULL, COPYFILE_XATTR); 573 + .Ed 574 + .Sh SEE ALSO 575 + .Xr listxattr 2 , 576 + .Xr getxattr 2 , 577 + .Xr setxattr 2 , 578 + .Xr acl 3 579 + .Sh BUGS 580 + Both 581 + .Fn copyfile 582 + functions lack a way to set the input or output block size. 583 + .Pp 584 + Recursive copies do not honor hard links. 585 + .Sh HISTORY 586 + The 587 + .Fn copyfile 588 + API was introduced in Mac OS X 10.5.
+4156
src/copyfile/copyfile.c
··· 1 + // Modified by Lubos Dolezel for Darling 2 + /* 3 + * Copyright (c) 2004-2010 Apple, Inc. All rights reserved. 4 + * 5 + * @APPLE_LICENSE_HEADER_START@ 6 + * 7 + * This file contains Original Code and/or Modifications of Original Code 8 + * as defined in and that are subject to the Apple Public Source License 9 + * Version 2.0 (the 'License'). You may not use this file except in 10 + * compliance with the License. Please obtain a copy of the License at 11 + * http://www.opensource.apple.com/apsl/ and read it before using this 12 + * file. 13 + * 14 + * The Original Code and all software distributed under the License are 15 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 + * Please see the License for the specific language governing rights and 20 + * limitations under the License. 21 + * 22 + * @APPLE_LICENSE_HEADER_END@ 23 + */ 24 + 25 + #include <err.h> 26 + #include <errno.h> 27 + #include <sys/types.h> 28 + #include <sys/acl.h> 29 + #include <stdio.h> 30 + #include <stdlib.h> 31 + #include <string.h> 32 + #include <stdint.h> 33 + #include <syslog.h> 34 + #include <unistd.h> 35 + #include <fcntl.h> 36 + #include <sys/errno.h> 37 + #include <sys/stat.h> 38 + #include <sys/time.h> 39 + #include <sys/xattr.h> 40 + #include <sys/attr.h> 41 + #include <sys/syscall.h> 42 + #include <sys/param.h> 43 + #include <sys/mount.h> 44 + #include <sys/acl.h> 45 + #include <libkern/OSByteOrder.h> 46 + #include <membership.h> 47 + #include <fts.h> 48 + #include <libgen.h> 49 + 50 + #ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION 51 + # include <Kernel/sys/decmpfs.h> 52 + #endif 53 + 54 + #include <TargetConditionals.h> 55 + #if !TARGET_OS_IPHONE && !defined(DARLING) 56 + #include <quarantine.h> 57 + 58 + #define XATTR_QUARANTINE_NAME qtn_xattr_name 59 + #else /* TARGET_OS_IPHONE */ 60 + #define qtn_file_t void * 61 + #define QTN_SERIALIZED_DATA_MAX 0 62 + static void * qtn_file_alloc(void) { return NULL; } 63 + static int qtn_file_init_with_fd(void *x, int y) { return -1; } 64 + static int qtn_file_init_with_path(void *x, const char *path) { return -1; } 65 + static int qtn_file_init_with_data(void *x, const void *data, size_t len) { return -1; } 66 + static void qtn_file_free(void *x) { return; } 67 + static int qtn_file_apply_to_fd(void *x, int y) { return 0; } 68 + static char *qtn_error(int x) { return NULL; } 69 + static int qtn_file_to_data(void *x, char *y, size_t z) { return -1; } 70 + static void *qtn_file_clone(void *x) { return NULL; } 71 + #define XATTR_QUARANTINE_NAME "figgledidiggledy" 72 + #endif /* TARGET_OS_IPHONE */ 73 + 74 + #include "copyfile.h" 75 + #include "copyfile_private.h" 76 + #include "xattr_flags.h" 77 + 78 + enum cfInternalFlags { 79 + cfDelayAce = 1 << 0, 80 + cfMakeFileInvisible = 1 << 1, 81 + cfSawDecmpEA = 1 << 2, 82 + }; 83 + 84 + /* 85 + * The state structure keeps track of 86 + * the source filename, the destination filename, their 87 + * associated file-descriptors, the stat infomration for the 88 + * source file, the security information for the source file, 89 + * the flags passed in for the copy, a pointer to place statistics 90 + * (not currently implemented), debug flags, and a pointer to callbacks 91 + * (not currently implemented). 92 + */ 93 + struct _copyfile_state 94 + { 95 + char *src; 96 + char *dst; 97 + int src_fd; 98 + int dst_fd; 99 + struct stat sb; 100 + filesec_t fsec; 101 + copyfile_flags_t flags; 102 + unsigned int internal_flags; 103 + void *stats; 104 + uint32_t debug; 105 + copyfile_callback_t statuscb; 106 + void *ctx; 107 + qtn_file_t qinfo; /* Quarantine information -- probably NULL */ 108 + filesec_t original_fsec; 109 + filesec_t permissive_fsec; 110 + off_t totalCopied; 111 + int err; 112 + char *xattr_name; 113 + xattr_operation_intent_t copyIntent; 114 + }; 115 + 116 + struct acl_entry { 117 + u_int32_t ae_magic; 118 + #define _ACL_ENTRY_MAGIC 0xac1ac101 119 + u_int32_t ae_tag; 120 + guid_t ae_applicable; 121 + u_int32_t ae_flags; 122 + u_int32_t ae_perms; 123 + }; 124 + 125 + #define PACE(ace) do { \ 126 + struct acl_entry *__t = (struct acl_entry*)(ace); \ 127 + fprintf(stderr, "%s(%d): " #ace " = { flags = %#x, perms = %#x }\n", __FUNCTION__, __LINE__, __t->ae_flags, __t->ae_perms); \ 128 + } while (0) 129 + 130 + #define PACL(ace) \ 131 + do { \ 132 + ssize_t __l; char *__cp = acl_to_text(ace, &__l); \ 133 + fprintf(stderr, "%s(%d): " #ace " = %s\n", __FUNCTION__, __LINE__, __cp ? __cp : "(null)"); \ 134 + } while (0) 135 + 136 + static int 137 + acl_compare_permset_np(acl_permset_t p1, acl_permset_t p2) 138 + { 139 + struct pm { u_int32_t ap_perms; } *ps1, *ps2; 140 + ps1 = (struct pm*) p1; 141 + ps2 = (struct pm*) p2; 142 + 143 + return ((ps1->ap_perms == ps2->ap_perms) ? 1 : 0); 144 + } 145 + 146 + 147 + static int 148 + doesdecmpfs(int fd) { 149 + #ifdef DECMPFS_XATTR_NAME 150 + int rv; 151 + struct attrlist attrs; 152 + char volroot[MAXPATHLEN + 1]; 153 + struct statfs sfs; 154 + struct { 155 + uint32_t length; 156 + vol_capabilities_attr_t volAttrs; 157 + } volattrs; 158 + 159 + (void)fstatfs(fd, &sfs); 160 + strlcpy(volroot, sfs.f_mntonname, sizeof(volroot)); 161 + 162 + memset(&attrs, 0, sizeof(attrs)); 163 + attrs.bitmapcount = ATTR_BIT_MAP_COUNT; 164 + attrs.volattr = ATTR_VOL_CAPABILITIES; 165 + 166 + rv = getattrlist(volroot, &attrs, &volattrs, sizeof(volattrs), 0); 167 + 168 + if (rv != -1 && 169 + (volattrs.volAttrs.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_DECMPFS_COMPRESSION) && 170 + (volattrs.volAttrs.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_DECMPFS_COMPRESSION)) { 171 + return 1; 172 + } 173 + #endif 174 + return 0; 175 + } 176 + 177 + 178 + static void 179 + sort_xattrname_list(void *start, size_t length) 180 + { 181 + char **ptrs = NULL; 182 + int nel; 183 + char *tmp; 184 + int indx = 0; 185 + 186 + /* If it's not a proper C string at the end, don't do anything */ 187 + if (((char*)start)[length] != 0) 188 + return; 189 + /* 190 + * In order to sort the list of names, we need to 191 + * make a list of pointers to strings. To do that, 192 + * we need to run through the buffer, and find the 193 + * beginnings of strings. 194 + */ 195 + nel = 10; // Most files don't have many EAs 196 + ptrs = (char**)calloc(nel, sizeof(char*)); 197 + 198 + if (ptrs == NULL) 199 + goto done; 200 + 201 + #ifdef DEBUG 202 + { 203 + char *curPtr = start; 204 + while (curPtr < (char*)start + length) { 205 + printf("%s\n", curPtr); 206 + curPtr += strlen(curPtr) + 1; 207 + } 208 + } 209 + #endif 210 + 211 + tmp = ptrs[indx++] = (char*)start; 212 + 213 + while (tmp = memchr(tmp, 0, ((char*)start + length) - tmp)) { 214 + if (indx == nel) { 215 + nel += 10; 216 + ptrs = realloc(ptrs, sizeof(char**) * nel); 217 + if (ptrs == NULL) 218 + goto done; 219 + } 220 + ptrs[indx++] = ++tmp; 221 + } 222 + #ifdef DEBUG 223 + printf("Unsorted:\n"); 224 + for (nel = 0; nel < indx-1; nel++) { 225 + printf("\tEA %d = `%s'\n", nel, ptrs[nel]); 226 + } 227 + #endif 228 + qsort_b(ptrs, indx-1, sizeof(char*), ^(const void *left, const void *right) { 229 + int rv; 230 + char *lstr = *(char**)left, *rstr = *(char**)right; 231 + rv = strcmp(lstr, rstr); 232 + return rv; 233 + }); 234 + #ifdef DEBUG 235 + printf("Sorted:\n"); 236 + for (nel = 0; nel < indx-1; nel++) { 237 + printf("\tEA %d = `%s'\n", nel, ptrs[nel]); 238 + } 239 + #endif 240 + /* 241 + * Now that it's sorted, we need to make a copy, so we can 242 + * move the strings around into the new order. Then we 243 + * copy that on top of the old buffer, and we're done. 244 + */ 245 + char *copy = malloc(length); 246 + if (copy) { 247 + int i; 248 + char *curPtr = copy; 249 + 250 + for (i = 0; i < indx-1; i++) { 251 + size_t len = strlen(ptrs[i]); 252 + memcpy(curPtr, ptrs[i], len+1); 253 + curPtr += len+1; 254 + } 255 + memcpy(start, copy, length); 256 + free(copy); 257 + } 258 + 259 + done: 260 + if (ptrs) 261 + free(ptrs); 262 + return; 263 + } 264 + 265 + /* 266 + * Internally, the process is broken into a series of 267 + * private functions. 268 + */ 269 + static int copyfile_open (copyfile_state_t); 270 + static int copyfile_close (copyfile_state_t); 271 + static int copyfile_data (copyfile_state_t); 272 + static int copyfile_stat (copyfile_state_t); 273 + static int copyfile_security (copyfile_state_t); 274 + static int copyfile_xattr (copyfile_state_t); 275 + static int copyfile_pack (copyfile_state_t); 276 + static int copyfile_unpack (copyfile_state_t); 277 + 278 + static copyfile_flags_t copyfile_check (copyfile_state_t); 279 + static filesec_t copyfile_fix_perms(copyfile_state_t, filesec_t *); 280 + static int copyfile_preamble(copyfile_state_t *s, copyfile_flags_t flags); 281 + static int copyfile_internal(copyfile_state_t state, copyfile_flags_t flags); 282 + static int copyfile_unset_posix_fsec(filesec_t); 283 + static int copyfile_quarantine(copyfile_state_t); 284 + 285 + #define COPYFILE_DEBUG (1<<31) 286 + #define COPYFILE_DEBUG_VAR "COPYFILE_DEBUG" 287 + 288 + #ifndef _COPYFILE_TEST 289 + # define copyfile_warn(str, ...) syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__) 290 + # define copyfile_debug(d, str, ...) \ 291 + do { \ 292 + if (s && (d <= s->debug)) {\ 293 + syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \ 294 + } \ 295 + } while (0) 296 + #else 297 + #define copyfile_warn(str, ...) \ 298 + fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : "") 299 + # define copyfile_debug(d, str, ...) \ 300 + do { \ 301 + if (s && (d <= s->debug)) {\ 302 + fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \ 303 + } \ 304 + } while(0) 305 + #endif 306 + 307 + #ifndef DARLING 308 + static int copyfile_quarantine(copyfile_state_t s) 309 + { 310 + int rv = 0; 311 + if (s->qinfo == NULL) 312 + { 313 + int error; 314 + s->qinfo = qtn_file_alloc(); 315 + if (s->qinfo == NULL) 316 + { 317 + rv = -1; 318 + goto done; 319 + } 320 + if ((error = qtn_file_init_with_fd(s->qinfo, s->src_fd)) != 0) 321 + { 322 + qtn_file_free(s->qinfo); 323 + s->qinfo = NULL; 324 + rv = -1; 325 + goto done; 326 + } 327 + } 328 + done: 329 + return rv; 330 + } 331 + #else 332 + static int copyfile_quarantine(copyfile_state_t s) { return 0; } 333 + #endif 334 + 335 + static int 336 + add_uberace(acl_t *acl) 337 + { 338 + acl_entry_t entry; 339 + acl_permset_t permset; 340 + uuid_t qual; 341 + 342 + if (mbr_uid_to_uuid(getuid(), qual) != 0) 343 + goto error_exit; 344 + 345 + /* 346 + * First, we create an entry, and give it the special name 347 + * of ACL_FIRST_ENTRY, thus guaranteeing it will be first. 348 + * After that, we clear out all the permissions in it, and 349 + * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and 350 + * WRITE_EXTATTRIBUTES. We put these into an ACE that allows 351 + * the functionality, and put this into the ACL. 352 + */ 353 + if (acl_create_entry_np(acl, &entry, ACL_FIRST_ENTRY) == -1) 354 + goto error_exit; 355 + if (acl_get_permset(entry, &permset) == -1) { 356 + copyfile_warn("acl_get_permset"); 357 + goto error_exit; 358 + } 359 + if (acl_clear_perms(permset) == -1) { 360 + copyfile_warn("acl_clear_permset"); 361 + goto error_exit; 362 + } 363 + if (acl_add_perm(permset, ACL_WRITE_DATA) == -1) { 364 + copyfile_warn("add ACL_WRITE_DATA"); 365 + goto error_exit; 366 + } 367 + if (acl_add_perm(permset, ACL_WRITE_ATTRIBUTES) == -1) { 368 + copyfile_warn("add ACL_WRITE_ATTRIBUTES"); 369 + goto error_exit; 370 + } 371 + if (acl_add_perm(permset, ACL_WRITE_EXTATTRIBUTES) == -1) { 372 + copyfile_warn("add ACL_WRITE_EXTATTRIBUTES"); 373 + goto error_exit; 374 + } 375 + if (acl_add_perm(permset, ACL_APPEND_DATA) == -1) { 376 + copyfile_warn("add ACL_APPEND_DATA"); 377 + goto error_exit; 378 + } 379 + if (acl_add_perm(permset, ACL_WRITE_SECURITY) == -1) { 380 + copyfile_warn("add ACL_WRITE_SECURITY"); 381 + goto error_exit; 382 + } 383 + if (acl_set_tag_type(entry, ACL_EXTENDED_ALLOW) == -1) { 384 + copyfile_warn("set ACL_EXTENDED_ALLOW"); 385 + goto error_exit; 386 + } 387 + 388 + if(acl_set_permset(entry, permset) == -1) { 389 + copyfile_warn("acl_set_permset"); 390 + goto error_exit; 391 + } 392 + if(acl_set_qualifier(entry, qual) == -1) { 393 + copyfile_warn("acl_set_qualifier"); 394 + goto error_exit; 395 + } 396 + 397 + return 0; 398 + error_exit: 399 + return -1; 400 + } 401 + 402 + static int 403 + is_uberace(acl_entry_t ace) 404 + { 405 + int retval = 0; 406 + acl_permset_t perms, tperms; 407 + acl_t tacl; 408 + acl_entry_t tentry; 409 + acl_tag_t tag; 410 + guid_t *qual = NULL; 411 + uuid_t myuuid; 412 + 413 + // Who am I, and who is the ACE for? 414 + mbr_uid_to_uuid(geteuid(), myuuid); 415 + qual = (guid_t*)acl_get_qualifier(ace); 416 + 417 + // Need to create a temporary acl, so I can get the uberace template. 418 + tacl = acl_init(1); 419 + if (tacl == NULL) { 420 + goto done; 421 + } 422 + add_uberace(&tacl); 423 + if (acl_get_entry(tacl, ACL_FIRST_ENTRY, &tentry) != 0) { 424 + goto done; 425 + } 426 + acl_get_permset(tentry, &tperms); 427 + 428 + // Now I need to get 429 + acl_get_tag_type(ace, &tag); 430 + acl_get_permset(ace, &perms); 431 + 432 + if (tag == ACL_EXTENDED_ALLOW && 433 + (memcmp(qual, myuuid, sizeof(myuuid)) == 0) && 434 + acl_compare_permset_np(tperms, perms)) 435 + retval = 1; 436 + 437 + done: 438 + 439 + if (qual) 440 + acl_free(qual); 441 + 442 + if (tacl) 443 + acl_free(tacl); 444 + 445 + return retval; 446 + } 447 + 448 + static void 449 + remove_uberace(int fd, struct stat *sbuf) 450 + { 451 + filesec_t fsec = NULL; 452 + acl_t acl = NULL; 453 + acl_entry_t entry; 454 + struct stat sb; 455 + 456 + fsec = filesec_init(); 457 + if (fsec == NULL) { 458 + goto noacl; 459 + } 460 + 461 + if (fstatx_np(fd, &sb, fsec) != 0) { 462 + if (errno == ENOTSUP) 463 + goto noacl; 464 + goto done; 465 + } 466 + 467 + if (filesec_get_property(fsec, FILESEC_ACL, &acl) != 0) { 468 + goto done; 469 + } 470 + 471 + if (acl_get_entry(acl, ACL_FIRST_ENTRY, &entry) == 0) { 472 + if (is_uberace(entry)) 473 + { 474 + mode_t m = sbuf->st_mode & ~S_IFMT; 475 + 476 + if (acl_delete_entry(acl, entry) != 0 || 477 + filesec_set_property(fsec, FILESEC_ACL, &acl) != 0 || 478 + filesec_set_property(fsec, FILESEC_MODE, &m) != 0 || 479 + fchmodx_np(fd, fsec) != 0) 480 + goto noacl; 481 + } 482 + } 483 + 484 + done: 485 + if (acl) 486 + acl_free(acl); 487 + if (fsec) 488 + filesec_free(fsec); 489 + return; 490 + 491 + noacl: 492 + fchmod(fd, sbuf->st_mode & ~S_IFMT); 493 + goto done; 494 + } 495 + 496 + static void 497 + reset_security(copyfile_state_t s) 498 + { 499 + /* If we haven't reset the file security information 500 + * (COPYFILE_SECURITY is not set in flags) 501 + * restore back the permissions the file had originally 502 + * 503 + * One of the reasons this seems so complicated is that 504 + * it is partially at odds with copyfile_security(). 505 + * 506 + * Simplisticly, we are simply trying to make sure we 507 + * only copy what was requested, and that we don't stomp 508 + * on what wasn't requested. 509 + */ 510 + 511 + #ifdef COPYFILE_RECURSIVE 512 + if (s->dst_fd > -1) { 513 + struct stat sbuf; 514 + 515 + if (s->src_fd > -1 && (s->flags & COPYFILE_STAT)) 516 + fstat(s->src_fd, &sbuf); 517 + else 518 + fstat(s->dst_fd, &sbuf); 519 + 520 + if (!(s->internal_flags & cfDelayAce)) 521 + remove_uberace(s->dst_fd, &sbuf); 522 + } 523 + #else 524 + if (s->permissive_fsec && (s->flags & COPYFILE_SECURITY) != COPYFILE_SECURITY) { 525 + if (s->flags & COPYFILE_ACL) { 526 + /* Just need to reset the BSD information -- mode, owner, group */ 527 + (void)fchown(s->dst_fd, s->dst_sb.st_uid, s->dst_sb.st_gid); 528 + (void)fchmod(s->dst_fd, s->dst_sb.st_mode); 529 + } else { 530 + /* 531 + * flags is either COPYFILE_STAT, or neither; if it's 532 + * neither, then we restore both ACL and POSIX permissions; 533 + * if it's STAT, however, then we only want to restore the 534 + * ACL (which may be empty). We do that by removing the 535 + * POSIX information from the filesec object. 536 + */ 537 + if (s->flags & COPYFILE_STAT) { 538 + copyfile_unset_posix_fsec(s->original_fsec); 539 + } 540 + if (fchmodx_np(s->dst_fd, s->original_fsec) < 0 && errno != ENOTSUP) 541 + copyfile_warn("restoring security information"); 542 + } 543 + } 544 + 545 + if (s->permissive_fsec) { 546 + filesec_free(s->permissive_fsec); 547 + s->permissive_fsec = NULL; 548 + } 549 + 550 + if (s->original_fsec) { 551 + filesec_free(s->original_fsec); 552 + s->original_fsec = NULL; 553 + } 554 + #endif 555 + 556 + return; 557 + } 558 + 559 + /* 560 + * copytree -- recursively copy a hierarchy. 561 + * 562 + * Unlike normal copyfile(), copytree() can copy an entire hierarchy. 563 + * Care is taken to keep the ACLs set up correctly, in addition to the 564 + * normal copying that is done. (When copying a hierarchy, we can't 565 + * get rid of the "allow-all-writes" ACE on a directory until we're done 566 + * copying the *contents* of the directory.) 567 + * 568 + * The other big difference from copyfile (for the moment) is that copytree() 569 + * will use a call-back function to pass along information about what is 570 + * about to be copied, and whether or not it succeeded. 571 + * 572 + * copytree() is called from copyfile() -- but copytree() itself then calls 573 + * copyfile() to copy each individual object. 574 + * 575 + * XXX - no effort is made to handle overlapping hierarchies at the moment. 576 + * 577 + */ 578 + 579 + static int 580 + copytree(copyfile_state_t s) 581 + { 582 + char *slash; 583 + int retval = 0; 584 + int (*sfunc)(const char *, struct stat *); 585 + copyfile_callback_t status = NULL; 586 + char srcisdir = 0, dstisdir = 0, dstexists = 0; 587 + struct stat sbuf; 588 + char *src, *dst; 589 + const char *dstpathsep = ""; 590 + #ifdef NOTYET 591 + char srcpath[PATH_MAX * 2 + 1], dstpath[PATH_MAX * 2 + 1]; 592 + #endif 593 + char *srcroot; 594 + FTS *fts = NULL; 595 + FTSENT *ftsent; 596 + ssize_t offset = 0; 597 + const char *paths[2] = { 0 }; 598 + unsigned int flags = 0; 599 + int fts_flags = FTS_NOCHDIR; 600 + 601 + if (s == NULL) { 602 + errno = EINVAL; 603 + retval = -1; 604 + goto done; 605 + } 606 + if (s->flags & (COPYFILE_MOVE | COPYFILE_UNLINK | COPYFILE_CHECK | COPYFILE_PACK | COPYFILE_UNPACK)) { 607 + errno = EINVAL; 608 + retval = -1; 609 + goto done; 610 + } 611 + 612 + flags = s->flags & (COPYFILE_ALL | COPYFILE_NOFOLLOW | COPYFILE_VERBOSE); 613 + 614 + paths[0] = src = s->src; 615 + dst = s->dst; 616 + 617 + if (src == NULL || dst == NULL) { 618 + errno = EINVAL; 619 + retval = -1; 620 + goto done; 621 + } 622 + 623 + sfunc = (flags & COPYFILE_NOFOLLOW_SRC) ? lstat : stat; 624 + if ((sfunc)(src, &sbuf) == -1) { 625 + retval = -1; 626 + goto done; 627 + } 628 + if ((sbuf.st_mode & S_IFMT) == S_IFDIR) { 629 + srcisdir = 1; 630 + } 631 + 632 + sfunc = (flags & COPYFILE_NOFOLLOW_DST) ? lstat : stat; 633 + if ((sfunc)(dst, &sbuf) == -1) { 634 + if (errno != ENOENT) { 635 + retval = -1; 636 + goto done; 637 + } 638 + } else { 639 + dstexists = 1; 640 + if ((sbuf.st_mode & S_IFMT) == S_IFDIR) { 641 + dstisdir = 1; 642 + } 643 + } 644 + 645 + #ifdef NOTYET 646 + // This doesn't handle filesystem crossing and case sensitivity 647 + // So there's got to be a better way 648 + 649 + if (realpath(src, srcpath) == NULL) { 650 + retval = -1; 651 + goto done; 652 + } 653 + 654 + if (realpath(dst, dstpath) == NULL && 655 + (errno == ENOENT && realpath(dirname(dst), dstpath) == NULL)) { 656 + retval = -1; 657 + goto done; 658 + } 659 + if (strstr(srcpath, dstpath) != NULL) { 660 + errno = EINVAL; 661 + retval = -1; 662 + goto done; 663 + } 664 + #endif 665 + srcroot = basename((char*)src); 666 + if (srcroot == NULL) { 667 + retval = -1; 668 + goto done; 669 + } 670 + 671 + /* 672 + * To work on as well: 673 + * We have a few cases when copying a hierarchy: 674 + * 1) src is a non-directory, dst is a directory; 675 + * 2) src is a non-directory, dst is a non-directory; 676 + * 3) src is a non-directory, dst does not exist; 677 + * 4) src is a directory, dst is a directory; 678 + * 5) src is a directory, dst is a non-directory; 679 + * 6) src is a directory, dst does not exist 680 + * 681 + * (1) copies src to dst/basename(src). 682 + * (2) fails if COPYFILE_EXCLUSIVE is set, otherwise copies src to dst. 683 + * (3) and (6) copy src to the name dst. 684 + * (4) copies the contents of src to the contents of dst. 685 + * (5) is an error. 686 + */ 687 + 688 + if (dstisdir) { 689 + // copy /path/to/src to /path/to/dst/src 690 + // Append "/" and (fts_path - strlen(basename(src))) to dst? 691 + dstpathsep = "/"; 692 + slash = strrchr(src, '/'); 693 + if (slash == NULL) 694 + offset = 0; 695 + else 696 + offset = slash - src + 1; 697 + } else { 698 + // copy /path/to/src to /path/to/dst 699 + // append (fts_path + strlen(src)) to dst? 700 + dstpathsep = ""; 701 + offset = strlen(src); 702 + } 703 + 704 + if (s->flags | COPYFILE_NOFOLLOW_SRC) 705 + fts_flags |= FTS_PHYSICAL; 706 + else 707 + fts_flags |= FTS_LOGICAL; 708 + 709 + fts = fts_open((char * const *)paths, fts_flags, NULL); 710 + 711 + status = s->statuscb; 712 + while ((ftsent = fts_read(fts)) != NULL) { 713 + int rv = 0; 714 + char *dstfile = NULL; 715 + int cmd = 0; 716 + copyfile_state_t tstate = copyfile_state_alloc(); 717 + if (tstate == NULL) { 718 + errno = ENOMEM; 719 + retval = -1; 720 + break; 721 + } 722 + tstate->statuscb = s->statuscb; 723 + tstate->ctx = s->ctx; 724 + asprintf(&dstfile, "%s%s%s", dst, dstpathsep, ftsent->fts_path + offset); 725 + if (dstfile == NULL) { 726 + copyfile_state_free(tstate); 727 + errno = ENOMEM; 728 + retval = -1; 729 + break; 730 + } 731 + switch (ftsent->fts_info) { 732 + case FTS_D: 733 + tstate->internal_flags |= cfDelayAce; 734 + cmd = COPYFILE_RECURSE_DIR; 735 + break; 736 + case FTS_SL: 737 + case FTS_SLNONE: 738 + case FTS_DEFAULT: 739 + case FTS_F: 740 + cmd = COPYFILE_RECURSE_FILE; 741 + break; 742 + case FTS_DP: 743 + cmd = COPYFILE_RECURSE_DIR_CLEANUP; 744 + break; 745 + case FTS_DNR: 746 + case FTS_ERR: 747 + case FTS_NS: 748 + case FTS_NSOK: 749 + default: 750 + errno = ftsent->fts_errno; 751 + if (status) { 752 + rv = (*status)(COPYFILE_RECURSE_ERROR, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx); 753 + if (rv == COPYFILE_SKIP || rv == COPYFILE_CONTINUE) { 754 + errno = 0; 755 + goto skipit; 756 + } 757 + if (rv == COPYFILE_QUIT) { 758 + retval = -1; 759 + goto stopit; 760 + } 761 + } else { 762 + retval = -1; 763 + goto stopit; 764 + } 765 + case FTS_DOT: 766 + goto skipit; 767 + 768 + } 769 + 770 + if (cmd == COPYFILE_RECURSE_DIR || cmd == COPYFILE_RECURSE_FILE) { 771 + if (status) { 772 + rv = (*status)(cmd, COPYFILE_START, tstate, ftsent->fts_path, dstfile, s->ctx); 773 + if (rv == COPYFILE_SKIP) { 774 + if (cmd == COPYFILE_RECURSE_DIR) { 775 + rv = fts_set(fts, ftsent, FTS_SKIP); 776 + if (rv == -1) { 777 + rv = (*status)(0, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx); 778 + if (rv == COPYFILE_QUIT) 779 + retval = -1; 780 + } 781 + } 782 + goto skipit; 783 + } 784 + if (rv == COPYFILE_QUIT) { 785 + retval = -1; errno = 0; 786 + goto stopit; 787 + } 788 + } 789 + int tmp_flags = (cmd == COPYFILE_RECURSE_DIR) ? (flags & ~COPYFILE_STAT) : flags; 790 + rv = copyfile(ftsent->fts_path, dstfile, tstate, tmp_flags); 791 + if (rv < 0) { 792 + if (status) { 793 + rv = (*status)(cmd, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx); 794 + if (rv == COPYFILE_QUIT) { 795 + retval = -1; 796 + goto stopit; 797 + } else 798 + rv = 0; 799 + goto skipit; 800 + } else { 801 + retval = -1; 802 + goto stopit; 803 + } 804 + } 805 + if (status) { 806 + rv = (*status)(cmd, COPYFILE_FINISH, tstate, ftsent->fts_path, dstfile, s->ctx); 807 + if (rv == COPYFILE_QUIT) { 808 + retval = -1; errno = 0; 809 + goto stopit; 810 + } 811 + } 812 + } else if (cmd == COPYFILE_RECURSE_DIR_CLEANUP) { 813 + if (status) { 814 + rv = (*status)(cmd, COPYFILE_START, tstate, ftsent->fts_path, dstfile, s->ctx); 815 + if (rv == COPYFILE_QUIT) { 816 + retval = -1; errno = 0; 817 + goto stopit; 818 + } else if (rv == COPYFILE_SKIP) { 819 + rv = 0; 820 + goto skipit; 821 + } 822 + } 823 + rv = copyfile(ftsent->fts_path, dstfile, tstate, (flags & COPYFILE_NOFOLLOW) | COPYFILE_STAT); 824 + if (rv < 0) { 825 + if (status) { 826 + rv = (*status)(COPYFILE_RECURSE_DIR_CLEANUP, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx); 827 + if (rv == COPYFILE_QUIT) { 828 + retval = -1; 829 + goto stopit; 830 + } else if (rv == COPYFILE_SKIP || rv == COPYFILE_CONTINUE) { 831 + if (rv == COPYFILE_CONTINUE) 832 + errno = 0; 833 + retval = 0; 834 + goto skipit; 835 + } 836 + } else { 837 + retval = -1; 838 + goto stopit; 839 + } 840 + } else { 841 + if (status) { 842 + rv = (*status)(COPYFILE_RECURSE_DIR_CLEANUP, COPYFILE_FINISH, tstate, ftsent->fts_path, dstfile, s->ctx); 843 + if (rv == COPYFILE_QUIT) { 844 + retval = -1; errno = 0; 845 + goto stopit; 846 + } 847 + } 848 + } 849 + 850 + rv = 0; 851 + } 852 + skipit: 853 + stopit: 854 + copyfile_state_free(tstate); 855 + free(dstfile); 856 + if (retval == -1) 857 + break; 858 + } 859 + 860 + done: 861 + if (fts) 862 + fts_close(fts); 863 + 864 + return retval; 865 + } 866 + 867 + /* 868 + * fcopyfile() is used to copy a source file descriptor to a destination file 869 + * descriptor. This allows an application to figure out how it wants to open 870 + * the files (doing various security checks, perhaps), and then just pass in 871 + * the file descriptors. 872 + */ 873 + int fcopyfile(int src_fd, int dst_fd, copyfile_state_t state, copyfile_flags_t flags) 874 + { 875 + int ret = 0; 876 + copyfile_state_t s = state; 877 + struct stat dst_sb; 878 + 879 + if (src_fd < 0 || dst_fd < 0) 880 + { 881 + errno = EINVAL; 882 + return -1; 883 + } 884 + 885 + if (copyfile_preamble(&s, flags) < 0) 886 + return -1; 887 + 888 + copyfile_debug(2, "set src_fd <- %d", src_fd); 889 + if (s->src_fd == -2 && src_fd > -1) 890 + { 891 + s->src_fd = src_fd; 892 + if (fstatx_np(s->src_fd, &s->sb, s->fsec) != 0) 893 + { 894 + if (errno == ENOTSUP || errno == EPERM) 895 + fstat(s->src_fd, &s->sb); 896 + else 897 + { 898 + copyfile_warn("fstatx_np on src fd %d", s->src_fd); 899 + return -1; 900 + } 901 + } 902 + } 903 + 904 + /* prevent copying on unsupported types */ 905 + switch (s->sb.st_mode & S_IFMT) 906 + { 907 + case S_IFLNK: 908 + case S_IFDIR: 909 + case S_IFREG: 910 + break; 911 + default: 912 + errno = ENOTSUP; 913 + return -1; 914 + } 915 + 916 + copyfile_debug(2, "set dst_fd <- %d", dst_fd); 917 + if (s->dst_fd == -2 && dst_fd > -1) 918 + s->dst_fd = dst_fd; 919 + 920 + (void)fstat(s->dst_fd, &dst_sb); 921 + (void)fchmod(s->dst_fd, (dst_sb.st_mode & ~S_IFMT) | (S_IRUSR | S_IWUSR)); 922 + 923 + (void)copyfile_quarantine(s); 924 + 925 + ret = copyfile_internal(s, flags); 926 + 927 + if (ret >= 0 && !(s->flags & COPYFILE_STAT)) 928 + { 929 + (void)fchmod(s->dst_fd, dst_sb.st_mode & ~S_IFMT); 930 + } 931 + 932 + if (s->err) { 933 + errno = s->err; 934 + s->err = 0; 935 + } 936 + if (state == NULL) { 937 + int t = errno; 938 + copyfile_state_free(s); 939 + errno = t; 940 + } 941 + 942 + return ret; 943 + 944 + } 945 + 946 + /* 947 + * the original copyfile() routine; this copies a source file to a destination 948 + * file. Note that because we need to set the names in the state variable, this 949 + * is not just the same as opening the two files, and then calling fcopyfile(). 950 + * Oh, if only life were that simple! 951 + */ 952 + int copyfile(const char *src, const char *dst, copyfile_state_t state, copyfile_flags_t flags) 953 + { 954 + int ret = 0; 955 + int createdst = 0; 956 + copyfile_state_t s = state; 957 + struct stat dst_sb; 958 + 959 + if (src == NULL && dst == NULL) 960 + { 961 + errno = EINVAL; 962 + return -1; 963 + } 964 + 965 + if (copyfile_preamble(&s, flags) < 0) 966 + { 967 + return -1; 968 + } 969 + 970 + /* 971 + * This macro is... well, it's not the worst thing you can do with cpp, not 972 + * by a long shot. Essentially, we are setting the filename (src or dst) 973 + * in the state structure; since the structure may not have been cleared out 974 + * before being used again, we do some of the cleanup here: if the given 975 + * filename (e.g., src) is set, and state->src is not equal to that, then 976 + * we need to check to see if the file descriptor had been opened, and if so, 977 + * close it. After that, we set state->src to be a copy of the given filename, 978 + * releasing the old copy if necessary. 979 + */ 980 + #define COPYFILE_SET_FNAME(NAME, S) \ 981 + do { \ 982 + if (NAME != NULL) { \ 983 + if (S->NAME != NULL && strncmp(NAME, S->NAME, MAXPATHLEN)) { \ 984 + copyfile_debug(2, "replacing string %s (%s) -> (%s)", #NAME, NAME, S->NAME);\ 985 + if (S->NAME##_fd != -2 && S->NAME##_fd > -1) { \ 986 + copyfile_debug(4, "closing %s fd: %d", #NAME, S->NAME##_fd); \ 987 + close(S->NAME##_fd); \ 988 + S->NAME##_fd = -2; \ 989 + } \ 990 + } \ 991 + if (S->NAME) { \ 992 + free(S->NAME); \ 993 + S->NAME = NULL; \ 994 + } \ 995 + if ((NAME) && (S->NAME = strdup(NAME)) == NULL) \ 996 + return -1; \ 997 + } \ 998 + } while (0) 999 + 1000 + COPYFILE_SET_FNAME(src, s); 1001 + COPYFILE_SET_FNAME(dst, s); 1002 + 1003 + if (s->flags & COPYFILE_RECURSIVE) { 1004 + ret = copytree(s); 1005 + goto exit; 1006 + } 1007 + 1008 + /* 1009 + * Get a copy of the source file's security settings 1010 + */ 1011 + if (s->original_fsec) { 1012 + filesec_free(s->original_fsec); 1013 + s->original_fsec = NULL; 1014 + } 1015 + if ((s->original_fsec = filesec_init()) == NULL) 1016 + goto error_exit; 1017 + 1018 + if ((s->flags & COPYFILE_NOFOLLOW_DST) && lstat(s->dst, &dst_sb) == 0 && 1019 + ((dst_sb.st_mode & S_IFMT) == S_IFLNK)) { 1020 + if (s->permissive_fsec) 1021 + free(s->permissive_fsec); 1022 + s->permissive_fsec = NULL; 1023 + } else if(statx_np(s->dst, &dst_sb, s->original_fsec) == 0) 1024 + { 1025 + /* 1026 + * copyfile_fix_perms() will make a copy of the permission set, 1027 + * and insert at the beginning an ACE that ensures we can write 1028 + * to the file and set attributes. 1029 + */ 1030 + 1031 + if((s->permissive_fsec = copyfile_fix_perms(s, &s->original_fsec)) != NULL) 1032 + { 1033 + /* 1034 + * Set the permissions for the destination to our copy. 1035 + * We should get ENOTSUP from any filesystem that simply 1036 + * doesn't support it. 1037 + */ 1038 + if (chmodx_np(s->dst, s->permissive_fsec) < 0 && errno != ENOTSUP) 1039 + { 1040 + copyfile_warn("setting security information"); 1041 + filesec_free(s->permissive_fsec); 1042 + s->permissive_fsec = NULL; 1043 + } 1044 + } 1045 + } else if (errno == ENOENT) { 1046 + createdst = 1; 1047 + } 1048 + 1049 + /* 1050 + * If COPYFILE_CHECK is set in flags, then all we are going to do 1051 + * is see what kinds of things WOULD have been copied (see 1052 + * copyfile_check() below). We return that value. 1053 + */ 1054 + if (COPYFILE_CHECK & flags) 1055 + { 1056 + ret = copyfile_check(s); 1057 + goto exit; 1058 + } else if ((ret = copyfile_open(s)) < 0) 1059 + goto error_exit; 1060 + 1061 + (void)fcntl(s->src_fd, F_NOCACHE, 1); 1062 + (void)fcntl(s->dst_fd, F_NOCACHE, 1); 1063 + #ifdef F_SINGLE_WRITER 1064 + (void)fcntl(s->dst_fd, F_SINGLE_WRITER, 1); 1065 + #endif 1066 + 1067 + ret = copyfile_internal(s, flags); 1068 + if (ret == -1) 1069 + goto error_exit; 1070 + 1071 + #ifdef COPYFILE_RECURSIVE 1072 + if (!(flags & COPYFILE_STAT)) { 1073 + if (!createdst) 1074 + { 1075 + /* Just need to reset the BSD information -- mode, owner, group */ 1076 + (void)fchown(s->dst_fd, dst_sb.st_uid, dst_sb.st_gid); 1077 + (void)fchmod(s->dst_fd, dst_sb.st_mode); 1078 + } 1079 + } 1080 + #endif 1081 + 1082 + reset_security(s); 1083 + 1084 + if (s->src && (flags & COPYFILE_MOVE)) 1085 + (void)remove(s->src); 1086 + 1087 + exit: 1088 + if (state == NULL) { 1089 + int t = errno; 1090 + copyfile_state_free(s); 1091 + errno = t; 1092 + } 1093 + 1094 + return ret; 1095 + 1096 + error_exit: 1097 + ret = -1; 1098 + if (s->err) { 1099 + errno = s->err; 1100 + s->err = 0; 1101 + } 1102 + goto exit; 1103 + } 1104 + 1105 + /* 1106 + * Shared prelude to the {f,}copyfile(). This initializes the 1107 + * state variable, if necessary, and also checks for both debugging 1108 + * and disabling environment variables. 1109 + */ 1110 + static int copyfile_preamble(copyfile_state_t *state, copyfile_flags_t flags) 1111 + { 1112 + copyfile_state_t s; 1113 + 1114 + if (*state == NULL) 1115 + { 1116 + if ((*state = copyfile_state_alloc()) == NULL) 1117 + return -1; 1118 + } 1119 + 1120 + s = *state; 1121 + 1122 + if (COPYFILE_DEBUG & flags) 1123 + { 1124 + char *e; 1125 + if ((e = getenv(COPYFILE_DEBUG_VAR))) 1126 + { 1127 + errno = 0; 1128 + s->debug = (uint32_t)strtol(e, NULL, 0); 1129 + 1130 + /* clamp s->debug to 1 if the environment variable is not parsable */ 1131 + if (s->debug == 0 && errno != 0) 1132 + s->debug = 1; 1133 + } 1134 + copyfile_debug(2, "debug value set to: %d", s->debug); 1135 + } 1136 + 1137 + #if 0 1138 + /* Temporarily disabled */ 1139 + if (getenv(COPYFILE_DISABLE_VAR) != NULL) 1140 + { 1141 + copyfile_debug(1, "copyfile disabled"); 1142 + return 2; 1143 + } 1144 + #endif 1145 + copyfile_debug(2, "setting flags: %d", s->flags); 1146 + s->flags = flags; 1147 + 1148 + return 0; 1149 + } 1150 + 1151 + /* 1152 + * The guts of {f,}copyfile(). 1153 + * This looks through the flags in a particular order, and calls the 1154 + * associated functions. 1155 + */ 1156 + static int copyfile_internal(copyfile_state_t s, copyfile_flags_t flags) 1157 + { 1158 + int ret = 0; 1159 + 1160 + if (s->dst_fd < 0 || s->src_fd < 0) 1161 + { 1162 + copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", s->src_fd, s->dst_fd); 1163 + s->err = EINVAL; 1164 + return -1; 1165 + } 1166 + 1167 + /* 1168 + * COPYFILE_PACK causes us to create an Apple Double version of the 1169 + * source file, and puts it into the destination file. See 1170 + * copyfile_pack() below for all the gory details. 1171 + */ 1172 + if (COPYFILE_PACK & flags) 1173 + { 1174 + if ((ret = copyfile_pack(s)) < 0) 1175 + { 1176 + if (s->dst) unlink(s->dst); 1177 + goto exit; 1178 + } 1179 + goto exit; 1180 + } 1181 + 1182 + /* 1183 + * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously. 1184 + * The goal there is to take an Apple Double file, and turn it 1185 + * into a normal file (with data fork, resource fork, modes, 1186 + * extended attributes, ACLs, etc.). 1187 + */ 1188 + if (COPYFILE_UNPACK & flags) 1189 + { 1190 + if ((ret = copyfile_unpack(s)) < 0) 1191 + goto error_exit; 1192 + goto exit; 1193 + } 1194 + 1195 + /* 1196 + * If we have quarantine info set, we attempt 1197 + * to apply it to dst_fd. We don't care if 1198 + * it fails, not yet anyway. 1199 + */ 1200 + if (s->qinfo) { 1201 + int qr = qtn_file_apply_to_fd(s->qinfo, s->dst_fd); 1202 + if (qr != 0) { 1203 + if (s->statuscb) { 1204 + int rv; 1205 + 1206 + s->xattr_name = (char*)XATTR_QUARANTINE_NAME; 1207 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 1208 + s->xattr_name = NULL; 1209 + if (rv == COPYFILE_QUIT) { 1210 + s->err = errno = (qr < 0 ? ENOTSUP : qr); 1211 + ret = -1; 1212 + goto exit; 1213 + } 1214 + } else { 1215 + s->err = errno = (qr < 0 ? ENOTSUP : qr); 1216 + ret = -1; 1217 + goto exit; 1218 + } 1219 + } 1220 + } 1221 + 1222 + /* 1223 + * COPYFILE_XATTR tells us to copy the extended attributes; 1224 + * this is seperate from the extended security (aka ACLs), 1225 + * however. If we succeed in this, we continue to the next 1226 + * stage; if we fail, we return with an error value. Note 1227 + * that we fail if the errno is ENOTSUP, but we don't print 1228 + * a warning in that case. 1229 + */ 1230 + if (COPYFILE_XATTR & flags) 1231 + { 1232 + if ((ret = copyfile_xattr(s)) < 0) 1233 + { 1234 + if (errno != ENOTSUP && errno != EPERM) 1235 + copyfile_warn("error processing extended attributes"); 1236 + goto exit; 1237 + } 1238 + } 1239 + 1240 + /* 1241 + * Simialr to above, this tells us whether or not to copy 1242 + * the non-meta data portion of the file. We attempt to 1243 + * remove (via unlink) the destination file if we fail. 1244 + */ 1245 + if (COPYFILE_DATA & flags) 1246 + { 1247 + if ((ret = copyfile_data(s)) < 0) 1248 + { 1249 + copyfile_warn("error processing data"); 1250 + if (s->dst && unlink(s->dst)) 1251 + copyfile_warn("%s: remove", s->src ? s->src : "(null src)"); 1252 + goto exit; 1253 + } 1254 + } 1255 + 1256 + /* 1257 + * COPYFILE_SECURITY requests that we copy the security, both 1258 + * extended and mundane (that is, ACLs and POSIX). 1259 + */ 1260 + if (COPYFILE_SECURITY & flags) 1261 + { 1262 + if ((ret = copyfile_security(s)) < 0) 1263 + { 1264 + copyfile_warn("error processing security information"); 1265 + goto exit; 1266 + } 1267 + } 1268 + 1269 + if (COPYFILE_STAT & flags) 1270 + { 1271 + if ((ret = copyfile_stat(s)) < 0) 1272 + { 1273 + copyfile_warn("error processing POSIX information"); 1274 + goto exit; 1275 + } 1276 + } 1277 + 1278 + exit: 1279 + return ret; 1280 + 1281 + error_exit: 1282 + ret = -1; 1283 + goto exit; 1284 + } 1285 + 1286 + /* 1287 + * A publicly-visible routine, copyfile_state_alloc() sets up the state variable. 1288 + */ 1289 + copyfile_state_t copyfile_state_alloc(void) 1290 + { 1291 + copyfile_state_t s = (copyfile_state_t) calloc(1, sizeof(struct _copyfile_state)); 1292 + 1293 + if (s != NULL) 1294 + { 1295 + s->src_fd = -2; 1296 + s->dst_fd = -2; 1297 + if (s->fsec) { 1298 + filesec_free(s->fsec); 1299 + s->fsec = NULL; 1300 + } 1301 + s->fsec = filesec_init(); 1302 + } else 1303 + errno = ENOMEM; 1304 + 1305 + return s; 1306 + } 1307 + 1308 + /* 1309 + * copyfile_state_free() returns the memory allocated to the state structure. 1310 + * It also closes the file descriptors, if they've been opened. 1311 + */ 1312 + int copyfile_state_free(copyfile_state_t s) 1313 + { 1314 + if (s != NULL) 1315 + { 1316 + if (s->fsec) 1317 + filesec_free(s->fsec); 1318 + 1319 + if (s->original_fsec) 1320 + filesec_free(s->original_fsec); 1321 + 1322 + if (s->permissive_fsec) 1323 + filesec_free(s->permissive_fsec); 1324 + 1325 + if (s->qinfo) 1326 + qtn_file_free(s->qinfo); 1327 + 1328 + if (copyfile_close(s) < 0) 1329 + { 1330 + copyfile_warn("error closing files"); 1331 + return -1; 1332 + } 1333 + if (s->xattr_name) 1334 + free(s->xattr_name); 1335 + if (s->dst) 1336 + free(s->dst); 1337 + if (s->src) 1338 + free(s->src); 1339 + free(s); 1340 + } 1341 + return 0; 1342 + } 1343 + 1344 + /* 1345 + * Should we worry if we can't close the source? NFS says we 1346 + * should, but it's pretty late for us at this point. 1347 + */ 1348 + static int copyfile_close(copyfile_state_t s) 1349 + { 1350 + if (s->src && s->src_fd >= 0) 1351 + close(s->src_fd); 1352 + 1353 + if (s->dst && s->dst_fd >= 0) { 1354 + if (close(s->dst_fd)) 1355 + return -1; 1356 + } 1357 + 1358 + return 0; 1359 + } 1360 + 1361 + /* 1362 + * The purpose of this function is to set up a set of permissions 1363 + * (ACL and traditional) that lets us write to the file. In the 1364 + * case of ACLs, we do this by putting in a first entry that lets 1365 + * us write data, attributes, and extended attributes. In the case 1366 + * of traditional permissions, we set the S_IWUSR (user-write) 1367 + * bit. 1368 + */ 1369 + static filesec_t copyfile_fix_perms(copyfile_state_t s __unused, filesec_t *fsec) 1370 + { 1371 + filesec_t ret_fsec = NULL; 1372 + mode_t mode; 1373 + acl_t acl = NULL; 1374 + 1375 + if ((ret_fsec = filesec_dup(*fsec)) == NULL) 1376 + goto error_exit; 1377 + 1378 + if (filesec_get_property(ret_fsec, FILESEC_ACL, &acl) == 0) 1379 + { 1380 + #ifdef COPYFILE_RECURSIVE 1381 + if (add_uberace(&acl)) 1382 + goto error_exit; 1383 + #else 1384 + acl_entry_t entry; 1385 + acl_permset_t permset; 1386 + uuid_t qual; 1387 + 1388 + if (mbr_uid_to_uuid(getuid(), qual) != 0) 1389 + goto error_exit; 1390 + 1391 + /* 1392 + * First, we create an entry, and give it the special name 1393 + * of ACL_FIRST_ENTRY, thus guaranteeing it will be first. 1394 + * After that, we clear out all the permissions in it, and 1395 + * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and 1396 + * WRITE_EXTATTRIBUTES. We put these into an ACE that allows 1397 + * the functionality, and put this into the ACL. 1398 + */ 1399 + if (acl_create_entry_np(&acl, &entry, ACL_FIRST_ENTRY) == -1) 1400 + goto error_exit; 1401 + if (acl_get_permset(entry, &permset) == -1) 1402 + goto error_exit; 1403 + if (acl_clear_perms(permset) == -1) 1404 + goto error_exit; 1405 + if (acl_add_perm(permset, ACL_WRITE_DATA) == -1) 1406 + goto error_exit; 1407 + if (acl_add_perm(permset, ACL_WRITE_ATTRIBUTES) == -1) 1408 + goto error_exit; 1409 + if (acl_add_perm(permset, ACL_WRITE_EXTATTRIBUTES) == -1) 1410 + goto error_exit; 1411 + if (acl_set_tag_type(entry, ACL_EXTENDED_ALLOW) == -1) 1412 + goto error_exit; 1413 + 1414 + if(acl_set_permset(entry, permset) == -1) 1415 + goto error_exit; 1416 + if(acl_set_qualifier(entry, qual) == -1) 1417 + goto error_exit; 1418 + #endif 1419 + 1420 + if (filesec_set_property(ret_fsec, FILESEC_ACL, &acl) != 0) 1421 + goto error_exit; 1422 + } 1423 + 1424 + /* 1425 + * This is for the normal, mundane, POSIX permission model. 1426 + * We make sure that we can write to the file. 1427 + */ 1428 + if (filesec_get_property(ret_fsec, FILESEC_MODE, &mode) == 0) 1429 + { 1430 + if ((mode & (S_IWUSR | S_IRUSR)) != (S_IWUSR | S_IRUSR)) 1431 + { 1432 + mode |= S_IWUSR|S_IRUSR; 1433 + if (filesec_set_property(ret_fsec, FILESEC_MODE, &mode) != 0) 1434 + goto error_exit; 1435 + } 1436 + } 1437 + 1438 + exit: 1439 + if (acl) 1440 + acl_free(acl); 1441 + 1442 + return ret_fsec; 1443 + 1444 + error_exit: 1445 + if (ret_fsec) 1446 + { 1447 + filesec_free(ret_fsec); 1448 + ret_fsec = NULL; 1449 + } 1450 + goto exit; 1451 + } 1452 + 1453 + /* 1454 + * Used to clear out the BSD/POSIX security information from 1455 + * a filesec 1456 + */ 1457 + static int 1458 + copyfile_unset_posix_fsec(filesec_t fsec) 1459 + { 1460 + (void)filesec_set_property(fsec, FILESEC_OWNER, _FILESEC_UNSET_PROPERTY); 1461 + (void)filesec_set_property(fsec, FILESEC_GROUP, _FILESEC_UNSET_PROPERTY); 1462 + (void)filesec_set_property(fsec, FILESEC_MODE, _FILESEC_UNSET_PROPERTY); 1463 + return 0; 1464 + } 1465 + 1466 + /* 1467 + * Used to remove acl information from a filesec_t 1468 + * Unsetting the acl alone in Tiger was insufficient 1469 + */ 1470 + static int copyfile_unset_acl(copyfile_state_t s) 1471 + { 1472 + int ret = 0; 1473 + if (filesec_set_property(s->fsec, FILESEC_ACL, NULL) == -1) 1474 + { 1475 + copyfile_debug(5, "unsetting acl attribute on %s", s->dst ? s->dst : "(null dst)"); 1476 + ++ret; 1477 + } 1478 + if (filesec_set_property(s->fsec, FILESEC_UUID, NULL) == -1) 1479 + { 1480 + copyfile_debug(5, "unsetting uuid attribute on %s", s->dst ? s->dst : "(null dst)"); 1481 + ++ret; 1482 + } 1483 + if (filesec_set_property(s->fsec, FILESEC_GRPUUID, NULL) == -1) 1484 + { 1485 + copyfile_debug(5, "unsetting group uuid attribute on %s", s->dst ? s->dst : "(null dst)"); 1486 + ++ret; 1487 + } 1488 + return ret; 1489 + } 1490 + 1491 + /* 1492 + * copyfile_open() does what one expects: it opens up the files 1493 + * given in the state structure, if they're not already open. 1494 + * It also does some type validation, to ensure that we only 1495 + * handle file types we know about. 1496 + */ 1497 + static int copyfile_open(copyfile_state_t s) 1498 + { 1499 + int oflags = O_EXCL | O_CREAT | O_WRONLY; 1500 + int islnk = 0, isdir = 0; 1501 + int osrc = 0, dsrc = 0; 1502 + 1503 + if (s->src && s->src_fd == -2) 1504 + { 1505 + if ((COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np) 1506 + (s->src, &s->sb, s->fsec)) 1507 + { 1508 + copyfile_warn("stat on %s", s->src); 1509 + return -1; 1510 + } 1511 + 1512 + /* prevent copying on unsupported types */ 1513 + switch (s->sb.st_mode & S_IFMT) 1514 + { 1515 + case S_IFLNK: 1516 + islnk = 1; 1517 + if ((size_t)s->sb.st_size > SIZE_T_MAX) { 1518 + s->err = ENOMEM; /* too big for us to copy */ 1519 + return -1; 1520 + } 1521 + osrc = O_SYMLINK; 1522 + break; 1523 + case S_IFDIR: 1524 + isdir = 1; 1525 + break; 1526 + case S_IFREG: 1527 + break; 1528 + default: 1529 + if (!(strcmp(s->src, "/dev/null") == 0 && (s->flags & COPYFILE_METADATA))) { 1530 + s->err = ENOTSUP; 1531 + return -1; 1532 + } 1533 + } 1534 + /* 1535 + * If we're packing, then we are actually 1536 + * creating a file, no matter what the source 1537 + * was. 1538 + */ 1539 + if (s->flags & COPYFILE_PACK) { 1540 + /* 1541 + * O_SYMLINK and O_NOFOLLOW are not compatible options: 1542 + * if the file is a symlink, and O_NOFOLLOW is specified, 1543 + * open will return ELOOP, whether or not O_SYMLINK is set. 1544 + * However, we know whether or not it was a symlink from 1545 + * the stat above (although there is a potentiaal for a race 1546 + * condition here, but it will err on the side of returning 1547 + * ELOOP from open). 1548 + */ 1549 + if (!islnk) 1550 + osrc = (s->flags & COPYFILE_NOFOLLOW_SRC) ? O_NOFOLLOW : 0; 1551 + isdir = islnk = 0; 1552 + } 1553 + 1554 + if ((s->src_fd = open(s->src, O_RDONLY | osrc , 0)) < 0) 1555 + { 1556 + copyfile_warn("open on %s", s->src); 1557 + return -1; 1558 + } else 1559 + copyfile_debug(2, "open successful on source (%s)", s->src); 1560 + 1561 + (void)copyfile_quarantine(s); 1562 + } 1563 + 1564 + if (s->dst && s->dst_fd == -2) 1565 + { 1566 + /* 1567 + * COPYFILE_UNLINK tells us to try removing the destination 1568 + * before we create it. We don't care if the file doesn't 1569 + * exist, so we ignore ENOENT. 1570 + */ 1571 + if (COPYFILE_UNLINK & s->flags) 1572 + { 1573 + if (remove(s->dst) < 0 && errno != ENOENT) 1574 + { 1575 + copyfile_warn("%s: remove", s->dst); 1576 + return -1; 1577 + } 1578 + } 1579 + 1580 + if (s->flags & COPYFILE_NOFOLLOW_DST) { 1581 + struct stat st; 1582 + 1583 + dsrc = O_NOFOLLOW; 1584 + if (lstat(s->dst, &st) != -1) { 1585 + if ((st.st_mode & S_IFMT) == S_IFLNK) 1586 + dsrc = O_SYMLINK; 1587 + } 1588 + } 1589 + 1590 + if (islnk) { 1591 + size_t sz = (size_t)s->sb.st_size + 1; 1592 + char *bp; 1593 + 1594 + bp = calloc(1, sz); 1595 + if (bp == NULL) { 1596 + copyfile_warn("cannot allocate %zd bytes", sz); 1597 + return -1; 1598 + } 1599 + if (readlink(s->src, bp, sz-1) == -1) { 1600 + copyfile_warn("cannot readlink %s", s->src); 1601 + free(bp); 1602 + return -1; 1603 + } 1604 + if (symlink(bp, s->dst) == -1) { 1605 + if (errno != EEXIST || (s->flags & COPYFILE_EXCL)) { 1606 + copyfile_warn("Cannot make symlink %s", s->dst); 1607 + free(bp); 1608 + return -1; 1609 + } 1610 + } 1611 + free(bp); 1612 + s->dst_fd = open(s->dst, O_RDONLY | O_SYMLINK); 1613 + if (s->dst_fd == -1) { 1614 + copyfile_warn("Cannot open symlink %s for reading", s->dst); 1615 + return -1; 1616 + } 1617 + } else if (isdir) { 1618 + mode_t mode; 1619 + mode = (s->sb.st_mode & ~S_IFMT) | S_IRWXU; 1620 + 1621 + if (mkdir(s->dst, mode) == -1) { 1622 + if (errno != EEXIST || (s->flags & COPYFILE_EXCL)) { 1623 + copyfile_warn("Cannot make directory %s", s->dst); 1624 + return -1; 1625 + } 1626 + } 1627 + s->dst_fd = open(s->dst, O_RDONLY | dsrc); 1628 + if (s->dst_fd == -1) { 1629 + copyfile_warn("Cannot open directory %s for reading", s->dst); 1630 + return -1; 1631 + } 1632 + } else while((s->dst_fd = open(s->dst, oflags | dsrc, s->sb.st_mode | S_IWUSR)) < 0) 1633 + { 1634 + /* 1635 + * We set S_IWUSR because fsetxattr does not -- at the time this comment 1636 + * was written -- allow one to set an extended attribute on a file descriptor 1637 + * for a read-only file, even if the file descriptor is opened for writing. 1638 + * This will only matter if the file does not already exist. 1639 + */ 1640 + switch(errno) 1641 + { 1642 + case EEXIST: 1643 + copyfile_debug(3, "open failed, retrying (%s)", s->dst); 1644 + if (s->flags & COPYFILE_EXCL) 1645 + break; 1646 + oflags = oflags & ~O_CREAT; 1647 + if (s->flags & (COPYFILE_PACK | COPYFILE_DATA)) 1648 + { 1649 + copyfile_debug(4, "truncating existing file (%s)", s->dst); 1650 + oflags |= O_TRUNC; 1651 + } 1652 + continue; 1653 + case EACCES: 1654 + if(chmod(s->dst, (s->sb.st_mode | S_IWUSR) & ~S_IFMT) == 0) 1655 + continue; 1656 + else { 1657 + /* 1658 + * If we're trying to write to a directory to which we don't 1659 + * have access, the create above would have failed, but chmod 1660 + * here would have given us ENOENT. But the real error is 1661 + * still one of access, so we change the errno we're reporting. 1662 + * This could cause confusion with a race condition. 1663 + */ 1664 + 1665 + if (errno == ENOENT) 1666 + errno = EACCES; 1667 + break; 1668 + } 1669 + case EISDIR: 1670 + copyfile_debug(3, "open failed because it is a directory (%s)", s->dst); 1671 + if (((s->flags & COPYFILE_EXCL) || 1672 + (!isdir && (s->flags & COPYFILE_DATA))) 1673 + && !(s->flags & COPYFILE_UNPACK)) 1674 + break; 1675 + oflags = (oflags & ~(O_WRONLY|O_CREAT|O_TRUNC)) | O_RDONLY; 1676 + continue; 1677 + } 1678 + copyfile_warn("open on %s", s->dst); 1679 + return -1; 1680 + } 1681 + copyfile_debug(2, "open successful on destination (%s)", s->dst); 1682 + } 1683 + 1684 + if (s->dst_fd < 0 || s->src_fd < 0) 1685 + { 1686 + copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", 1687 + s->src_fd, s->dst_fd); 1688 + s->err = EINVAL; 1689 + return -1; 1690 + } 1691 + return 0; 1692 + } 1693 + 1694 + 1695 + /* 1696 + * copyfile_check(), as described above, essentially tells you 1697 + * what you'd have to copy, if you wanted it to copy the things 1698 + * you asked it to copy. 1699 + * In other words, if you pass in COPYFILE_ALL, and the file in 1700 + * question had no extended attributes but did have an ACL, you'd 1701 + * get back COPYFILE_ACL. 1702 + */ 1703 + static copyfile_flags_t copyfile_check(copyfile_state_t s) 1704 + { 1705 + acl_t acl = NULL; 1706 + copyfile_flags_t ret = 0; 1707 + int nofollow = (s->flags & COPYFILE_NOFOLLOW_SRC); 1708 + qtn_file_t qinfo; 1709 + 1710 + if (!s->src) 1711 + { 1712 + s->err = EINVAL; 1713 + return -1; 1714 + } 1715 + 1716 + /* check EAs */ 1717 + if (COPYFILE_XATTR & s->flags) 1718 + if (listxattr(s->src, 0, 0, nofollow ? XATTR_NOFOLLOW : 0) > 0) 1719 + { 1720 + ret |= COPYFILE_XATTR; 1721 + } 1722 + 1723 + if (COPYFILE_ACL & s->flags) 1724 + { 1725 + (COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np) 1726 + (s->src, &s->sb, s->fsec); 1727 + 1728 + if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) == 0) 1729 + ret |= COPYFILE_ACL; 1730 + } 1731 + 1732 + copyfile_debug(2, "check result: %d (%s)", ret, s->src); 1733 + 1734 + if (acl) 1735 + acl_free(acl); 1736 + 1737 + if (s->qinfo) { 1738 + /* If the state has had quarantine info set already, we use that */ 1739 + ret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL); 1740 + } else { 1741 + qinfo = qtn_file_alloc(); 1742 + /* 1743 + * For quarantine information, we need to see if the source file 1744 + * has any. Since it may be a symlink, however, and we may, or 1745 + * not be following, *and* there's no qtn* routine which can optionally 1746 + * follow or not follow a symlink, we need to instead work around 1747 + * this limitation. 1748 + */ 1749 + if (qinfo) { 1750 + int fd; 1751 + int qret = 0; 1752 + struct stat sbuf; 1753 + 1754 + /* 1755 + * If we care about not following symlinks, *and* the file exists 1756 + * (which is to say, lstat doesn't return an error), *and* the file 1757 + * is a symlink, then we open it up (with O_SYMLINK), and use 1758 + * qtn_file_init_with_fd(); if none of that is true, however, then 1759 + * we can simply use qtn_file_init_with_path(). 1760 + */ 1761 + if (nofollow 1762 + && lstat(s->src, &sbuf) == 0 1763 + && ((sbuf.st_mode & S_IFMT) == S_IFLNK)) { 1764 + fd = open(s->src, O_RDONLY | O_SYMLINK); 1765 + if (fd != -1) { 1766 + if (!qtn_file_init_with_fd(qinfo, fd)) { 1767 + qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL); 1768 + } 1769 + close(fd); 1770 + } 1771 + } else { 1772 + if (!qtn_file_init_with_path(qinfo, s->src)) { 1773 + qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL); 1774 + } 1775 + } 1776 + qtn_file_free(qinfo); 1777 + ret |= qret; 1778 + } 1779 + } 1780 + return ret; 1781 + } 1782 + 1783 + /* 1784 + * Attempt to copy the data section of a file. Using blockisize 1785 + * is not necessarily the fastest -- it might be desirable to 1786 + * specify a blocksize, somehow. But it's a size that should be 1787 + * guaranteed to work. 1788 + */ 1789 + static int copyfile_data(copyfile_state_t s) 1790 + { 1791 + size_t blen; 1792 + char *bp = 0; 1793 + ssize_t nread; 1794 + int ret = 0; 1795 + size_t iBlocksize = 0; 1796 + size_t oBlocksize = 0; 1797 + const size_t onegig = 1 << 30; 1798 + struct statfs sfs; 1799 + copyfile_callback_t status = s->statuscb; 1800 + 1801 + /* Unless it's a normal file, we don't copy. For now, anyway */ 1802 + if ((s->sb.st_mode & S_IFMT) != S_IFREG) 1803 + return 0; 1804 + 1805 + #ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION 1806 + if (s->internal_flags & cfSawDecmpEA) { 1807 + if (s->sb.st_flags & UF_COMPRESSED) { 1808 + if ((s->flags & COPYFILE_STAT) == 0) { 1809 + if (fchflags(s->dst_fd, UF_COMPRESSED) == 0) { 1810 + goto exit; 1811 + } 1812 + } 1813 + } 1814 + } 1815 + #endif 1816 + 1817 + if (fstatfs(s->src_fd, &sfs) == -1) { 1818 + iBlocksize = s->sb.st_blksize; 1819 + } else { 1820 + iBlocksize = sfs.f_iosize; 1821 + } 1822 + 1823 + /* Work-around for 6453525, limit blocksize to 1G */ 1824 + if (iBlocksize > onegig) { 1825 + iBlocksize = onegig; 1826 + } 1827 + 1828 + if ((bp = malloc(iBlocksize)) == NULL) 1829 + return -1; 1830 + 1831 + if (fstatfs(s->dst_fd, &sfs) == -1 || sfs.f_iosize == 0) { 1832 + oBlocksize = iBlocksize; 1833 + } else { 1834 + oBlocksize = sfs.f_iosize; 1835 + if (oBlocksize > onegig) 1836 + oBlocksize = onegig; 1837 + } 1838 + 1839 + blen = iBlocksize; 1840 + 1841 + s->totalCopied = 0; 1842 + /* If supported, do preallocation for Xsan / HFS volumes */ 1843 + #ifdef F_PREALLOCATE 1844 + { 1845 + fstore_t fst; 1846 + 1847 + fst.fst_flags = 0; 1848 + fst.fst_posmode = F_PEOFPOSMODE; 1849 + fst.fst_offset = 0; 1850 + fst.fst_length = s->sb.st_size; 1851 + /* Ignore errors; this is merely advisory. */ 1852 + (void)fcntl(s->dst_fd, F_PREALLOCATE, &fst); 1853 + } 1854 + #endif 1855 + 1856 + while ((nread = read(s->src_fd, bp, blen)) > 0) 1857 + { 1858 + ssize_t nwritten; 1859 + size_t left = nread; 1860 + void *ptr = bp; 1861 + int loop = 0; 1862 + 1863 + while (left > 0) { 1864 + nwritten = write(s->dst_fd, ptr, MIN(left, oBlocksize)); 1865 + switch (nwritten) { 1866 + case 0: 1867 + if (++loop > 5) { 1868 + copyfile_warn("writing to output %d times resulted in 0 bytes written", loop); 1869 + ret = -1; 1870 + s->err = EAGAIN; 1871 + goto exit; 1872 + } 1873 + break; 1874 + case -1: 1875 + copyfile_warn("writing to output file got error"); 1876 + if (status) { 1877 + int rv = (*status)(COPYFILE_COPY_DATA, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 1878 + if (rv == COPYFILE_SKIP) { // Skip the data copy 1879 + ret = 0; 1880 + goto exit; 1881 + } 1882 + if (rv == COPYFILE_CONTINUE) { // Retry the write 1883 + errno = 0; 1884 + continue; 1885 + } 1886 + } 1887 + ret = -1; 1888 + goto exit; 1889 + default: 1890 + left -= nwritten; 1891 + ptr = ((char*)ptr) + nwritten; 1892 + loop = 0; 1893 + break; 1894 + } 1895 + s->totalCopied += nwritten; 1896 + if (status) { 1897 + int rv = (*status)(COPYFILE_COPY_DATA, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx); 1898 + if (rv == COPYFILE_QUIT) { 1899 + ret = -1; s->err = errno = ECANCELED; 1900 + goto exit; 1901 + } 1902 + } 1903 + } 1904 + } 1905 + if (nread < 0) 1906 + { 1907 + copyfile_warn("reading from %s", s->src ? s->src : "(null src)"); 1908 + ret = -1; 1909 + goto exit; 1910 + } 1911 + 1912 + if (ftruncate(s->dst_fd, s->totalCopied) < 0) 1913 + { 1914 + ret = -1; 1915 + goto exit; 1916 + } 1917 + 1918 + exit: 1919 + if (ret == -1) 1920 + { 1921 + s->err = errno; 1922 + } 1923 + free(bp); 1924 + return ret; 1925 + } 1926 + 1927 + /* 1928 + * copyfile_security() will copy the ACL set, and the 1929 + * POSIX set. Complexities come when dealing with 1930 + * inheritied permissions, and when dealing with both 1931 + * POSIX and ACL permissions. 1932 + */ 1933 + static int copyfile_security(copyfile_state_t s) 1934 + { 1935 + int copied = 0; 1936 + struct stat sb; 1937 + acl_t acl_src = NULL, acl_tmp = NULL, acl_dst = NULL; 1938 + int ret = 0; 1939 + filesec_t tmp_fsec = NULL; 1940 + filesec_t fsec_dst = filesec_init(); 1941 + 1942 + if (fsec_dst == NULL) 1943 + return -1; 1944 + 1945 + 1946 + if (COPYFILE_ACL & s->flags) 1947 + { 1948 + if (filesec_get_property(s->fsec, FILESEC_ACL, &acl_src)) 1949 + { 1950 + if (errno == ENOENT) 1951 + acl_src = NULL; 1952 + else 1953 + goto error_exit; 1954 + } 1955 + 1956 + /* grab the destination acl 1957 + cannot assume it's empty due to inheritance 1958 + */ 1959 + if(fstatx_np(s->dst_fd, &sb, fsec_dst)) 1960 + goto error_exit; 1961 + 1962 + if (filesec_get_property(fsec_dst, FILESEC_ACL, &acl_dst)) 1963 + { 1964 + if (errno == ENOENT) 1965 + acl_dst = NULL; 1966 + else 1967 + goto error_exit; 1968 + } 1969 + 1970 + if (acl_src == NULL && acl_dst == NULL) 1971 + goto no_acl; 1972 + 1973 + acl_tmp = acl_init(4); 1974 + if (acl_tmp == NULL) 1975 + goto error_exit; 1976 + 1977 + if (acl_src) { 1978 + acl_entry_t ace = NULL; 1979 + acl_entry_t tmp = NULL; 1980 + for (copied = 0; 1981 + acl_get_entry(acl_src, 1982 + ace == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY, 1983 + &ace) == 0;) 1984 + { 1985 + acl_flagset_t flags = { 0 }; 1986 + acl_get_flagset_np(ace, &flags); 1987 + if (!acl_get_flag_np(flags, ACL_ENTRY_INHERITED)) 1988 + { 1989 + if ((ret = acl_create_entry(&acl_tmp, &tmp)) == -1) 1990 + goto error_exit; 1991 + 1992 + if ((ret = acl_copy_entry(tmp, ace)) == -1) 1993 + goto error_exit; 1994 + 1995 + copyfile_debug(2, "copied acl entry from %s to %s", 1996 + s->src ? s->src : "(null src)", 1997 + s->dst ? s->dst : "(null tmp)"); 1998 + copied++; 1999 + } 2000 + } 2001 + } 2002 + if (acl_dst) { 2003 + acl_entry_t ace = NULL; 2004 + acl_entry_t tmp = NULL; 2005 + acl_flagset_t flags = { 0 }; 2006 + for (copied = 0;acl_get_entry(acl_dst, 2007 + ace == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY, 2008 + &ace) == 0;) 2009 + { 2010 + acl_get_flagset_np(ace, &flags); 2011 + if (acl_get_flag_np(flags, ACL_ENTRY_INHERITED)) 2012 + { 2013 + if ((ret = acl_create_entry(&acl_tmp, &tmp)) == -1) 2014 + goto error_exit; 2015 + 2016 + if ((ret = acl_copy_entry(tmp, ace)) == -1) 2017 + goto error_exit; 2018 + 2019 + copyfile_debug(2, "copied acl entry from %s to %s", 2020 + s->src ? s->src : "(null dst)", 2021 + s->dst ? s->dst : "(null tmp)"); 2022 + copied++; 2023 + } 2024 + } 2025 + } 2026 + if (!filesec_set_property(s->fsec, FILESEC_ACL, &acl_tmp)) 2027 + { 2028 + copyfile_debug(3, "altered acl"); 2029 + } 2030 + } 2031 + no_acl: 2032 + /* 2033 + * The following code is attempting to ensure that only the requested 2034 + * security information gets copied over to the destination file. 2035 + * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT, 2036 + * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in 2037 + * this function). 2038 + * 2039 + * If we have both flags, we copy everything; if we have ACL but not STAT, 2040 + * we remove the POSIX information from the filesec object, and apply the 2041 + * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore 2042 + * the extended version. 2043 + */ 2044 + tmp_fsec = filesec_dup(s->fsec); 2045 + if (tmp_fsec == NULL) { 2046 + goto error_exit; 2047 + } 2048 + 2049 + switch (COPYFILE_SECURITY & s->flags) { 2050 + case COPYFILE_ACL: 2051 + copyfile_unset_posix_fsec(tmp_fsec); 2052 + /* FALLTHROUGH */ 2053 + case COPYFILE_ACL | COPYFILE_STAT: 2054 + if (fchmodx_np(s->dst_fd, tmp_fsec) < 0) { 2055 + acl_t acl = NULL; 2056 + /* 2057 + * The call could have failed for a number of reasons, since 2058 + * it does a number of things: it changes the mode of the file, 2059 + * sets the owner and group, and applies an ACL (if one exists). 2060 + * The typical failure is going to be trying to set the group of 2061 + * the destination file to match the source file, when the process 2062 + * doesn't have permission to put files in that group. We try to 2063 + * work around this by breaking the steps out and doing them 2064 + * discretely. We don't care if the fchown fails, but we do care 2065 + * if the mode or ACL can't be set. For historical reasons, we 2066 + * simply log those failures, however. 2067 + * 2068 + * Big warning here: we may NOT have COPYFILE_STAT set, since 2069 + * we fell-through from COPYFILE_ACL. So check for the fchmod. 2070 + */ 2071 + 2072 + #define NS(x) ((x) ? (x) : "(null string)") 2073 + if ((s->flags & COPYFILE_STAT) && 2074 + fchmod(s->dst_fd, s->sb.st_mode) == -1) { 2075 + copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s->dst), NS(s->src)); 2076 + } 2077 + (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid); 2078 + if (filesec_get_property(tmp_fsec, FILESEC_ACL, &acl) == 0) { 2079 + if (acl_set_fd(s->dst_fd, acl) == -1) { 2080 + copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s->dst), NS(s->src)); 2081 + } 2082 + acl_free(acl); 2083 + } 2084 + } 2085 + #undef NS 2086 + break; 2087 + case COPYFILE_STAT: 2088 + (void)fchmod(s->dst_fd, s->sb.st_mode); 2089 + break; 2090 + } 2091 + filesec_free(tmp_fsec); 2092 + exit: 2093 + filesec_free(fsec_dst); 2094 + if (acl_src) acl_free(acl_src); 2095 + if (acl_dst) acl_free(acl_dst); 2096 + if (acl_tmp) acl_free(acl_tmp); 2097 + 2098 + return ret; 2099 + 2100 + error_exit: 2101 + ret = -1; 2102 + goto exit; 2103 + 2104 + } 2105 + 2106 + /* 2107 + * Attempt to set the destination file's stat information -- including 2108 + * flags and time-related fields -- to the source's. 2109 + */ 2110 + static int copyfile_stat(copyfile_state_t s) 2111 + { 2112 + struct timeval tval[2]; 2113 + unsigned int added_flags = 0, dst_flags = 0; 2114 + struct stat dst_sb; 2115 + 2116 + /* 2117 + * NFS doesn't support chflags; ignore errors as a result, since 2118 + * we don't return failure for this. 2119 + */ 2120 + if (s->internal_flags & cfMakeFileInvisible) 2121 + added_flags |= UF_HIDDEN; 2122 + 2123 + /* 2124 + * We need to check if SF_RESTRICTED was set on the destination 2125 + * by the kernel. If it was, don't drop it. 2126 + */ 2127 + if (fstat(s->dst_fd, &dst_sb)) 2128 + return -1; 2129 + if (dst_sb.st_flags & SF_RESTRICTED) 2130 + added_flags |= SF_RESTRICTED; 2131 + 2132 + /* Copy file flags, masking out any we don't want to preserve */ 2133 + dst_flags = (s->sb.st_flags & ~COPYFILE_OMIT_FLAGS) | added_flags; 2134 + (void)fchflags(s->dst_fd, dst_flags); 2135 + 2136 + /* If this fails, we don't care */ 2137 + (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid); 2138 + 2139 + /* This may have already been done in copyfile_security() */ 2140 + (void)fchmod(s->dst_fd, s->sb.st_mode & ~S_IFMT); 2141 + 2142 + tval[0].tv_sec = s->sb.st_atime; 2143 + tval[1].tv_sec = s->sb.st_mtime; 2144 + tval[0].tv_usec = tval[1].tv_usec = 0; 2145 + (void)futimes(s->dst_fd, tval); 2146 + 2147 + return 0; 2148 + } 2149 + 2150 + /* 2151 + * Similar to copyfile_security() in some ways; this 2152 + * routine copies the extended attributes from the source, 2153 + * and sets them on the destination. 2154 + * The procedure is pretty simple, even if it is verbose: 2155 + * for each named attribute on the destination, get its name, and 2156 + * remove it. We should have none after that. 2157 + * For each named attribute on the source, get its name, get its 2158 + * data, and set it on the destination. 2159 + */ 2160 + static int copyfile_xattr(copyfile_state_t s) 2161 + { 2162 + char *name; 2163 + char *namebuf, *end; 2164 + ssize_t xa_size; 2165 + void *xa_dataptr; 2166 + ssize_t bufsize = 4096; 2167 + ssize_t asize; 2168 + ssize_t nsize; 2169 + int ret = 0; 2170 + int look_for_decmpea = 0; 2171 + 2172 + /* delete EAs on destination */ 2173 + if ((nsize = flistxattr(s->dst_fd, 0, 0, 0)) > 0) 2174 + { 2175 + if ((namebuf = (char *) malloc(nsize)) == NULL) 2176 + return -1; 2177 + else 2178 + nsize = flistxattr(s->dst_fd, namebuf, nsize, 0); 2179 + 2180 + if (nsize > 0) { 2181 + /* 2182 + * With this, end points to the last byte of the allocated buffer 2183 + * This *should* be NUL, from flistxattr, but if it's not, we can 2184 + * set it anyway -- it'll result in a truncated name, which then 2185 + * shouldn't match when we get them later. 2186 + */ 2187 + end = namebuf + nsize - 1; 2188 + if (*end != 0) 2189 + *end = 0; 2190 + for (name = namebuf; name <= end; name += strlen(name) + 1) { 2191 + /* If the quarantine information shows up as an EA, we skip over it */ 2192 + if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0) { 2193 + continue; 2194 + } 2195 + fremovexattr(s->dst_fd, name,0); 2196 + } 2197 + } 2198 + free(namebuf); 2199 + } else 2200 + if (nsize < 0) 2201 + { 2202 + if (errno == ENOTSUP || errno == EPERM) 2203 + return 0; 2204 + else 2205 + return -1; 2206 + } 2207 + 2208 + #ifdef DECMPFS_XATTR_NAME 2209 + if ((s->flags & COPYFILE_DATA) && 2210 + (s->sb.st_flags & UF_COMPRESSED) && 2211 + doesdecmpfs(s->src_fd) && 2212 + doesdecmpfs(s->dst_fd)) { 2213 + look_for_decmpea = XATTR_SHOWCOMPRESSION; 2214 + } 2215 + #endif 2216 + 2217 + /* get name list of EAs on source */ 2218 + if ((nsize = flistxattr(s->src_fd, 0, 0, look_for_decmpea)) < 0) 2219 + { 2220 + if (errno == ENOTSUP || errno == EPERM) 2221 + return 0; 2222 + else 2223 + return -1; 2224 + } else 2225 + if (nsize == 0) 2226 + return 0; 2227 + 2228 + if ((namebuf = (char *) malloc(nsize)) == NULL) 2229 + return -1; 2230 + else 2231 + nsize = flistxattr(s->src_fd, namebuf, nsize, look_for_decmpea); 2232 + 2233 + if (nsize <= 0) { 2234 + free(namebuf); 2235 + return (int)nsize; 2236 + } 2237 + 2238 + /* 2239 + * With this, end points to the last byte of the allocated buffer 2240 + * This *should* be NUL, from flistxattr, but if it's not, we can 2241 + * set it anyway -- it'll result in a truncated name, which then 2242 + * shouldn't match when we get them later. 2243 + */ 2244 + end = namebuf + nsize - 1; 2245 + if (*end != 0) 2246 + *end = 0; 2247 + 2248 + if ((xa_dataptr = (void *) malloc(bufsize)) == NULL) { 2249 + free(namebuf); 2250 + return -1; 2251 + } 2252 + 2253 + for (name = namebuf; name <= end; name += strlen(name) + 1) 2254 + { 2255 + if (s->xattr_name) { 2256 + free(s->xattr_name); 2257 + s->xattr_name = NULL; 2258 + } 2259 + 2260 + /* If the quarantine information shows up as an EA, we skip over it */ 2261 + if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0) 2262 + continue; 2263 + 2264 + if ((xa_size = fgetxattr(s->src_fd, name, 0, 0, 0, look_for_decmpea)) < 0) 2265 + { 2266 + continue; 2267 + } 2268 + 2269 + if (xa_size > bufsize) 2270 + { 2271 + void *tdptr = xa_dataptr; 2272 + bufsize = xa_size; 2273 + if ((xa_dataptr = 2274 + (void *) realloc((void *) xa_dataptr, bufsize)) == NULL) 2275 + { 2276 + free(tdptr); 2277 + ret = -1; 2278 + continue; 2279 + } 2280 + } 2281 + 2282 + if ((asize = fgetxattr(s->src_fd, name, xa_dataptr, xa_size, 0, look_for_decmpea)) < 0) 2283 + { 2284 + continue; 2285 + } 2286 + 2287 + if (xa_size != asize) 2288 + xa_size = asize; 2289 + 2290 + #ifdef DECMPFS_XATTR_NAME 2291 + if (strncmp(name, DECMPFS_XATTR_NAME, end-name) == 0) 2292 + { 2293 + decmpfs_disk_header *hdr = xa_dataptr; 2294 + 2295 + /* 2296 + * If the EA has the decmpfs name, but is too 2297 + * small, or doesn't have the right magic number, 2298 + * or isn't the right type, we'll just skip it. 2299 + * This means it won't end up in the destination 2300 + * file, and data copy will happen normally. 2301 + */ 2302 + if ((size_t)xa_size < sizeof(decmpfs_disk_header)) { 2303 + continue; 2304 + } 2305 + if (OSSwapLittleToHostInt32(hdr->compression_magic) != DECMPFS_MAGIC) { 2306 + continue; 2307 + } 2308 + /* 2309 + * From AppleFSCompression documentation: 2310 + * "It is incumbent on the aware copy engine to identify 2311 + * the type of compression being used, and to perform an 2312 + * unaware copy of any file it does not recognize." 2313 + * 2314 + * Compression Types are defined in: 2315 + * "AppleFSCompression/Common/compressorCommon.h" 2316 + * 2317 + * Unfortunately, they don't provide a way to dynamically 2318 + * determine what possible compression_type values exist, 2319 + * so we have to update this every time a new compression_type 2320 + * is added (Types 7->10 were added in Yosemite) 2321 + * 2322 + * Ubiquity faulting file compression type 0x80000001 are 2323 + * deprecated as of Yosemite, per rdar://17714998 don't copy the 2324 + * decmpfs xattr on these files, zero byte files are safer 2325 + * than a fault nobody knows how to handle. 2326 + */ 2327 + switch (OSSwapLittleToHostInt32(hdr->compression_type)) { 2328 + case 3: /* zlib-compressed data in xattr */ 2329 + case 4: /* 64k chunked zlib-compressed data in resource fork */ 2330 + 2331 + case 7: /* LZVN-compressed data in xattr */ 2332 + case 8: /* 64k chunked LZVN-compressed data in resource fork */ 2333 + 2334 + case 9: /* uncompressed data in xattr (similar to but not identical to CMP_Type1) */ 2335 + case 10: /* 64k chunked uncompressed data in resource fork */ 2336 + 2337 + /* valid compression type, we want to copy. */ 2338 + break; 2339 + 2340 + case 5: /* specifies de-dup within the generation store. Don't copy decmpfs xattr. */ 2341 + copyfile_debug(3, "compression_type <5> on attribute com.apple.decmpfs for src file %s is not copied.", 2342 + s->src ? s->src : "(null string)"); 2343 + continue; 2344 + 2345 + case 6: /* unused */ 2346 + case 0x80000001: /* faulting files are deprecated, don't copy decmpfs xattr */ 2347 + default: 2348 + copyfile_warn("Invalid compression_type <%d> on attribute %s for src file %s", 2349 + OSSwapLittleToHostInt32(hdr->compression_type), name, s->src ? s->src : "(null string)"); 2350 + continue; 2351 + } 2352 + s->internal_flags |= cfSawDecmpEA; 2353 + } 2354 + #endif 2355 + 2356 + // If we have a copy intention stated, and the EA is to be ignored, we ignore it 2357 + if (s->copyIntent 2358 + && xattr_preserve_for_intent(name, s->copyIntent) == 0) 2359 + continue; 2360 + 2361 + s->xattr_name = strdup(name); 2362 + 2363 + if (s->statuscb) { 2364 + int rv; 2365 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx); 2366 + if (rv == COPYFILE_QUIT) { 2367 + s->err = ECANCELED; 2368 + goto out; 2369 + } else if (rv == COPYFILE_SKIP) { 2370 + continue; 2371 + } 2372 + } 2373 + if (fsetxattr(s->dst_fd, name, xa_dataptr, xa_size, 0, look_for_decmpea) < 0) 2374 + { 2375 + if (s->statuscb) 2376 + { 2377 + int rv; 2378 + if (s->xattr_name == NULL) 2379 + s->xattr_name = strdup(name); 2380 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 2381 + if (rv == COPYFILE_QUIT) 2382 + { 2383 + s->err = ECANCELED; 2384 + ret = -1; 2385 + goto out; 2386 + } 2387 + } 2388 + else 2389 + { 2390 + ret = -1; 2391 + copyfile_warn("could not set attributes %s on destination file descriptor: %s", name, strerror(errno)); 2392 + continue; 2393 + } 2394 + } 2395 + if (s->statuscb) { 2396 + int rv; 2397 + if (s->xattr_name == NULL) 2398 + s->xattr_name = strdup(name); 2399 + 2400 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx); 2401 + if (rv == COPYFILE_QUIT) { 2402 + s->err = ECANCELED; 2403 + goto out; 2404 + } 2405 + } 2406 + } 2407 + out: 2408 + if (namebuf) 2409 + free(namebuf); 2410 + free((void *) xa_dataptr); 2411 + if (s->xattr_name) { 2412 + free(s->xattr_name); 2413 + s->xattr_name = NULL; 2414 + } 2415 + return ret; 2416 + } 2417 + 2418 + /* 2419 + * API interface into getting data from the opaque data type. 2420 + */ 2421 + int copyfile_state_get(copyfile_state_t s, uint32_t flag, void *ret) 2422 + { 2423 + if (ret == NULL) 2424 + { 2425 + errno = EFAULT; 2426 + return -1; 2427 + } 2428 + 2429 + switch(flag) 2430 + { 2431 + case COPYFILE_STATE_SRC_FD: 2432 + *(int*)ret = s->src_fd; 2433 + break; 2434 + case COPYFILE_STATE_DST_FD: 2435 + *(int*)ret = s->dst_fd; 2436 + break; 2437 + case COPYFILE_STATE_SRC_FILENAME: 2438 + *(char**)ret = s->src; 2439 + break; 2440 + case COPYFILE_STATE_DST_FILENAME: 2441 + *(char**)ret = s->dst; 2442 + break; 2443 + case COPYFILE_STATE_QUARANTINE: 2444 + *(qtn_file_t*)ret = s->qinfo; 2445 + break; 2446 + #if 0 2447 + case COPYFILE_STATE_STATS: 2448 + ret = s->stats.global; 2449 + break; 2450 + case COPYFILE_STATE_PROGRESS_CB: 2451 + ret = s->callbacks.progress; 2452 + break; 2453 + #endif 2454 + #ifdef COPYFILE_STATE_STATUS_CB 2455 + case COPYFILE_STATE_STATUS_CB: 2456 + *(copyfile_callback_t*)ret = s->statuscb; 2457 + break; 2458 + case COPYFILE_STATE_STATUS_CTX: 2459 + *(void**)ret = s->ctx; 2460 + break; 2461 + case COPYFILE_STATE_COPIED: 2462 + *(off_t*)ret = s->totalCopied; 2463 + break; 2464 + #endif 2465 + #ifdef COPYFILE_STATE_XATTRNAME 2466 + case COPYFILE_STATE_XATTRNAME: 2467 + *(char**)ret = s->xattr_name; 2468 + break; 2469 + #endif 2470 + #ifdef COPYFILE_STATE_INTENT 2471 + case COPYFILE_STATE_INTENT: 2472 + *(xattr_operation_intent_t*)ret = s->copyIntent; 2473 + break; 2474 + #endif 2475 + default: 2476 + errno = EINVAL; 2477 + ret = NULL; 2478 + return -1; 2479 + } 2480 + return 0; 2481 + } 2482 + 2483 + /* 2484 + * Public API for setting state data (remember that the state is 2485 + * an opaque data type). 2486 + */ 2487 + int copyfile_state_set(copyfile_state_t s, uint32_t flag, const void * thing) 2488 + { 2489 + #define copyfile_set_string(DST, SRC) \ 2490 + do { \ 2491 + if (SRC != NULL) { \ 2492 + DST = strdup((char *)SRC); \ 2493 + } else { \ 2494 + if (DST != NULL) { \ 2495 + free(DST); \ 2496 + } \ 2497 + DST = NULL; \ 2498 + } \ 2499 + } while (0) 2500 + 2501 + if (thing == NULL) 2502 + { 2503 + errno = EFAULT; 2504 + return -1; 2505 + } 2506 + 2507 + switch(flag) 2508 + { 2509 + case COPYFILE_STATE_SRC_FD: 2510 + s->src_fd = *(int*)thing; 2511 + break; 2512 + case COPYFILE_STATE_DST_FD: 2513 + s->dst_fd = *(int*)thing; 2514 + break; 2515 + case COPYFILE_STATE_SRC_FILENAME: 2516 + copyfile_set_string(s->src, thing); 2517 + break; 2518 + case COPYFILE_STATE_DST_FILENAME: 2519 + copyfile_set_string(s->dst, thing); 2520 + break; 2521 + case COPYFILE_STATE_QUARANTINE: 2522 + if (s->qinfo) 2523 + { 2524 + qtn_file_free(s->qinfo); 2525 + s->qinfo = NULL; 2526 + } 2527 + if (*(qtn_file_t*)thing) 2528 + s->qinfo = qtn_file_clone(*(qtn_file_t*)thing); 2529 + break; 2530 + #if 0 2531 + case COPYFILE_STATE_STATS: 2532 + s->stats.global = thing; 2533 + break; 2534 + case COPYFILE_STATE_PROGRESS_CB: 2535 + s->callbacks.progress = thing; 2536 + break; 2537 + #endif 2538 + #ifdef COPYFILE_STATE_STATUS_CB 2539 + case COPYFILE_STATE_STATUS_CB: 2540 + s->statuscb = (copyfile_callback_t)thing; 2541 + break; 2542 + case COPYFILE_STATE_STATUS_CTX: 2543 + s->ctx = (void*)thing; 2544 + break; 2545 + #endif 2546 + #ifdef COPYFILE_STATE_INTENT 2547 + case COPYFILE_STATE_INTENT: 2548 + s->copyIntent = *(xattr_operation_intent_t*)thing; 2549 + break; 2550 + #endif 2551 + default: 2552 + errno = EINVAL; 2553 + return -1; 2554 + } 2555 + return 0; 2556 + #undef copyfile_set_string 2557 + } 2558 + 2559 + 2560 + /* 2561 + * Make this a standalone program for testing purposes by 2562 + * defining _COPYFILE_TEST. 2563 + */ 2564 + #ifdef _COPYFILE_TEST 2565 + #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x }, 2566 + 2567 + struct {char *s; int v;} opts[] = { 2568 + COPYFILE_OPTION(ACL) 2569 + COPYFILE_OPTION(STAT) 2570 + COPYFILE_OPTION(XATTR) 2571 + COPYFILE_OPTION(DATA) 2572 + COPYFILE_OPTION(SECURITY) 2573 + COPYFILE_OPTION(METADATA) 2574 + COPYFILE_OPTION(ALL) 2575 + COPYFILE_OPTION(NOFOLLOW_SRC) 2576 + COPYFILE_OPTION(NOFOLLOW_DST) 2577 + COPYFILE_OPTION(NOFOLLOW) 2578 + COPYFILE_OPTION(EXCL) 2579 + COPYFILE_OPTION(MOVE) 2580 + COPYFILE_OPTION(UNLINK) 2581 + COPYFILE_OPTION(PACK) 2582 + COPYFILE_OPTION(UNPACK) 2583 + COPYFILE_OPTION(CHECK) 2584 + COPYFILE_OPTION(VERBOSE) 2585 + COPYFILE_OPTION(DEBUG) 2586 + {NULL, 0} 2587 + }; 2588 + 2589 + int main(int c, char *v[]) 2590 + { 2591 + int i; 2592 + int flags = 0; 2593 + 2594 + if (c < 3) 2595 + errx(1, "insufficient arguments"); 2596 + 2597 + while(c-- > 3) 2598 + { 2599 + for (i = 0; opts[i].s != NULL; ++i) 2600 + { 2601 + if (strcasecmp(opts[i].s, v[c]) == 0) 2602 + { 2603 + printf("option %d: %s <- %d\n", c, opts[i].s, opts[i].v); 2604 + flags |= opts[i].v; 2605 + break; 2606 + } 2607 + } 2608 + } 2609 + 2610 + return copyfile(v[1], v[2], NULL, flags); 2611 + } 2612 + #endif 2613 + /* 2614 + * Apple Double Create 2615 + * 2616 + * Create an Apple Double "._" file from a file's extented attributes 2617 + * 2618 + * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. 2619 + */ 2620 + 2621 + 2622 + #define offsetof(type, member) ((size_t)(&((type *)0)->member)) 2623 + 2624 + #define XATTR_MAXATTRLEN (16*1024*1024) 2625 + 2626 + 2627 + /* 2628 + Typical "._" AppleDouble Header File layout: 2629 + ------------------------------------------------------------ 2630 + MAGIC 0x00051607 2631 + VERSION 0x00020000 2632 + FILLER 0 2633 + COUNT 2 2634 + .-- AD ENTRY[0] Finder Info Entry (must be first) 2635 + .--+-- AD ENTRY[1] Resource Fork Entry (must be last) 2636 + | '-> FINDER INFO 2637 + | ///////////// Fixed Size Data (32 bytes) 2638 + | EXT ATTR HDR 2639 + | ///////////// 2640 + | ATTR ENTRY[0] --. 2641 + | ATTR ENTRY[1] --+--. 2642 + | ATTR ENTRY[2] --+--+--. 2643 + | ... | | | 2644 + | ATTR ENTRY[N] --+--+--+--. 2645 + | ATTR DATA 0 <-' | | | 2646 + | //////////// | | | 2647 + | ATTR DATA 1 <----' | | 2648 + | ///////////// | | 2649 + | ATTR DATA 2 <-------' | 2650 + | ///////////// | 2651 + | ... | 2652 + | ATTR DATA N <----------' 2653 + | ///////////// 2654 + | Attribute Free Space 2655 + | 2656 + '----> RESOURCE FORK 2657 + ///////////// Variable Sized Data 2658 + ///////////// 2659 + ///////////// 2660 + ///////////// 2661 + ///////////// 2662 + ///////////// 2663 + ... 2664 + ///////////// 2665 + 2666 + ------------------------------------------------------------ 2667 + 2668 + NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are 2669 + stored as part of the Finder Info. The length in the Finder 2670 + Info AppleDouble entry includes the length of the extended 2671 + attribute header, attribute entries, and attribute data. 2672 + */ 2673 + 2674 + 2675 + /* 2676 + * On Disk Data Structures 2677 + * 2678 + * Note: Motorola 68K alignment and big-endian. 2679 + * 2680 + * See RFC 1740 for additional information about the AppleDouble file format. 2681 + * 2682 + */ 2683 + 2684 + #define ADH_MAGIC 0x00051607 2685 + #define ADH_VERSION 0x00020000 2686 + #define ADH_MACOSX "Mac OS X " 2687 + 2688 + /* 2689 + * AppleDouble Entry ID's 2690 + */ 2691 + #define AD_DATA 1 /* Data fork */ 2692 + #define AD_RESOURCE 2 /* Resource fork */ 2693 + #define AD_REALNAME 3 /* File's name on home file system */ 2694 + #define AD_COMMENT 4 /* Standard Mac comment */ 2695 + #define AD_ICONBW 5 /* Mac black & white icon */ 2696 + #define AD_ICONCOLOR 6 /* Mac color icon */ 2697 + #define AD_UNUSED 7 /* Not used */ 2698 + #define AD_FILEDATES 8 /* File dates; create, modify, etc */ 2699 + #define AD_FINDERINFO 9 /* Mac Finder info & extended info */ 2700 + #define AD_MACINFO 10 /* Mac file info, attributes, etc */ 2701 + #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */ 2702 + #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */ 2703 + #define AD_AFPNAME 13 /* Short name on AFP server */ 2704 + #define AD_AFPINFO 14 /* AFP file info, attrib., etc */ 2705 + #define AD_AFPDIRID 15 /* AFP directory ID */ 2706 + #define AD_ATTRIBUTES AD_FINDERINFO 2707 + 2708 + 2709 + #define ATTR_FILE_PREFIX "._" 2710 + #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */ 2711 + 2712 + #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */ 2713 + 2714 + /* Implementation Limits */ 2715 + #define ATTR_MAX_SIZE (16*1024*1024) /* 16 megabyte maximum attribute data size */ 2716 + #define ATTR_MAX_NAME_LEN 128 2717 + #define ATTR_MAX_HDR_SIZE (65536+18) 2718 + 2719 + /* 2720 + * Note: ATTR_MAX_HDR_SIZE is the largest attribute header 2721 + * size supported (including the attribute entries). All of 2722 + * the attribute entries must reside within this limit. 2723 + */ 2724 + 2725 + 2726 + #define FINDERINFOSIZE 32 2727 + 2728 + typedef struct apple_double_entry 2729 + { 2730 + u_int32_t type; /* entry type: see list, 0 invalid */ 2731 + u_int32_t offset; /* entry data offset from the beginning of the file. */ 2732 + u_int32_t length; /* entry data length in bytes. */ 2733 + } __attribute__((aligned(2), packed)) apple_double_entry_t; 2734 + 2735 + 2736 + typedef struct apple_double_header 2737 + { 2738 + u_int32_t magic; /* == ADH_MAGIC */ 2739 + u_int32_t version; /* format version: 2 = 0x00020000 */ 2740 + u_int32_t filler[4]; 2741 + u_int16_t numEntries; /* number of entries which follow */ 2742 + apple_double_entry_t entries[2]; /* 'finfo' & 'rsrc' always exist */ 2743 + u_int8_t finfo[FINDERINFOSIZE]; /* Must start with Finder Info (32 bytes) */ 2744 + u_int8_t pad[2]; /* get better alignment inside attr_header */ 2745 + } __attribute__((aligned(2), packed)) apple_double_header_t; 2746 + 2747 + 2748 + /* Entries are aligned on 4 byte boundaries */ 2749 + typedef struct attr_entry 2750 + { 2751 + u_int32_t offset; /* file offset to data */ 2752 + u_int32_t length; /* size of attribute data */ 2753 + u_int16_t flags; 2754 + u_int8_t namelen; /* length of name including NULL termination char */ 2755 + u_int8_t name[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */ 2756 + } __attribute__((aligned(2), packed)) attr_entry_t; 2757 + 2758 + 2759 + 2760 + /* Header + entries must fit into 64K */ 2761 + typedef struct attr_header 2762 + { 2763 + apple_double_header_t appledouble; 2764 + u_int32_t magic; /* == ATTR_HDR_MAGIC */ 2765 + u_int32_t debug_tag; /* for debugging == file id of owning file */ 2766 + u_int32_t total_size; /* total size of attribute header + entries + data */ 2767 + u_int32_t data_start; /* file offset to attribute data area */ 2768 + u_int32_t data_length; /* length of attribute data area */ 2769 + u_int32_t reserved[3]; 2770 + u_int16_t flags; 2771 + u_int16_t num_attrs; 2772 + } __attribute__((aligned(2), packed)) attr_header_t; 2773 + 2774 + /* Empty Resource Fork Header */ 2775 + /* This comes by way of xnu's vfs_xattr.c */ 2776 + typedef struct rsrcfork_header { 2777 + u_int32_t fh_DataOffset; 2778 + u_int32_t fh_MapOffset; 2779 + u_int32_t fh_DataLength; 2780 + u_int32_t fh_MapLength; 2781 + u_int8_t systemData[112]; 2782 + u_int8_t appData[128]; 2783 + u_int32_t mh_DataOffset; 2784 + u_int32_t mh_MapOffset; 2785 + u_int32_t mh_DataLength; 2786 + u_int32_t mh_MapLength; 2787 + u_int32_t mh_Next; 2788 + u_int16_t mh_RefNum; 2789 + u_int8_t mh_Attr; 2790 + u_int8_t mh_InMemoryAttr; 2791 + u_int16_t mh_Types; 2792 + u_int16_t mh_Names; 2793 + u_int16_t typeCount; 2794 + } __attribute__((aligned(2), packed)) rsrcfork_header_t; 2795 + #define RF_FIRST_RESOURCE 256 2796 + #define RF_NULL_MAP_LENGTH 30 2797 + #define RF_EMPTY_TAG "This resource fork intentionally left blank " 2798 + 2799 + static const rsrcfork_header_t empty_rsrcfork_header = { 2800 + OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // fh_DataOffset 2801 + OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // fh_MapOffset 2802 + 0, // fh_DataLength 2803 + OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH), // fh_MapLength 2804 + { RF_EMPTY_TAG, }, // systemData 2805 + { 0 }, // appData 2806 + OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // mh_DataOffset 2807 + OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // mh_MapOffset 2808 + 0, // mh_DataLength 2809 + OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH), // mh_MapLength 2810 + 0, // mh_Next 2811 + 0, // mh_RefNum 2812 + 0, // mh_Attr 2813 + 0, // mh_InMemoryAttr 2814 + OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH - 2), // mh_Types 2815 + OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH), // mh_Names 2816 + OSSwapHostToBigInt16(-1), // typeCount 2817 + }; 2818 + 2819 + #define SWAP16(x) OSSwapBigToHostInt16(x) 2820 + #define SWAP32(x) OSSwapBigToHostInt32(x) 2821 + #define SWAP64(x) OSSwapBigToHostInt64(x) 2822 + 2823 + #define ATTR_ALIGN 3L /* Use four-byte alignment */ 2824 + 2825 + #define ATTR_ENTRY_LENGTH(namelen) \ 2826 + ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN)) 2827 + 2828 + #define ATTR_NEXT(ae) \ 2829 + (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen)) 2830 + 2831 + #define XATTR_SECURITY_NAME "com.apple.acl.text" 2832 + 2833 + /* 2834 + * Endian swap Apple Double header 2835 + */ 2836 + static void 2837 + swap_adhdr(apple_double_header_t *adh) 2838 + { 2839 + #if BYTE_ORDER == LITTLE_ENDIAN 2840 + int count; 2841 + int i; 2842 + 2843 + count = (adh->magic == ADH_MAGIC) ? adh->numEntries : SWAP16(adh->numEntries); 2844 + 2845 + adh->magic = SWAP32 (adh->magic); 2846 + adh->version = SWAP32 (adh->version); 2847 + adh->numEntries = SWAP16 (adh->numEntries); 2848 + 2849 + for (i = 0; i < count; i++) 2850 + { 2851 + adh->entries[i].type = SWAP32 (adh->entries[i].type); 2852 + adh->entries[i].offset = SWAP32 (adh->entries[i].offset); 2853 + adh->entries[i].length = SWAP32 (adh->entries[i].length); 2854 + } 2855 + #else 2856 + (void)adh; 2857 + #endif 2858 + } 2859 + 2860 + /* 2861 + * Endian swap a single attr_entry_t 2862 + */ 2863 + static void 2864 + swap_attrhdr_entry(attr_entry_t *ae) 2865 + { 2866 + #if BYTE_ORDER == LITTLE_ENDIAN 2867 + ae->offset = SWAP32 (ae->offset); 2868 + ae->length = SWAP32 (ae->length); 2869 + ae->flags = SWAP16 (ae->flags); 2870 + #else 2871 + (void)ae; 2872 + #endif 2873 + } 2874 + 2875 + /* 2876 + * For a validated/endian swapped attr_header_t* 2877 + * ah, endian swap all of the entries. 2878 + */ 2879 + static void 2880 + swap_attrhdr_entries(attr_header_t *ah) 2881 + { 2882 + #if BYTE_ORDER == LITTLE_ENDIAN 2883 + int i; 2884 + int count; 2885 + attr_entry_t *entry; 2886 + attr_entry_t *next; 2887 + 2888 + /* If we're in copyfile_pack, num_args is native endian, 2889 + * if we're in _unpack, num_args is big endian. Use 2890 + * the magic number to test for endianess. 2891 + */ 2892 + count = (ah->magic == ATTR_HDR_MAGIC) ? ah->num_attrs : SWAP16(ah->num_attrs); 2893 + 2894 + entry = (attr_entry_t *)(&ah[1]); 2895 + for (i = 0; i < count; i++) { 2896 + next = ATTR_NEXT(entry); 2897 + swap_attrhdr_entry(entry); 2898 + entry = next; 2899 + } 2900 + #else 2901 + (void)ah; 2902 + #endif 2903 + } 2904 + 2905 + /* 2906 + * Endian swap extended attributes header 2907 + */ 2908 + static void 2909 + swap_attrhdr(attr_header_t *ah) 2910 + { 2911 + #if BYTE_ORDER == LITTLE_ENDIAN 2912 + ah->magic = SWAP32 (ah->magic); 2913 + ah->debug_tag = SWAP32 (ah->debug_tag); 2914 + ah->total_size = SWAP32 (ah->total_size); 2915 + ah->data_start = SWAP32 (ah->data_start); 2916 + ah->data_length = SWAP32 (ah->data_length); 2917 + ah->flags = SWAP16 (ah->flags); 2918 + ah->num_attrs = SWAP16 (ah->num_attrs); 2919 + #else 2920 + (void)ah; 2921 + #endif 2922 + } 2923 + 2924 + static const u_int32_t emptyfinfo[8] = {0}; 2925 + 2926 + /* 2927 + * Given an Apple Double file in src, turn it into a 2928 + * normal file (possibly with multiple forks, EAs, and 2929 + * ACLs) in dst. 2930 + */ 2931 + static int copyfile_unpack(copyfile_state_t s) 2932 + { 2933 + ssize_t bytes; 2934 + void * buffer, * endptr, * dataptr = NULL; 2935 + apple_double_header_t *adhdr; 2936 + ssize_t hdrsize; 2937 + int error = 0; 2938 + 2939 + if (s->sb.st_size < ATTR_MAX_HDR_SIZE) 2940 + hdrsize = (ssize_t)s->sb.st_size; 2941 + else 2942 + hdrsize = ATTR_MAX_HDR_SIZE; 2943 + 2944 + buffer = calloc(1, hdrsize); 2945 + if (buffer == NULL) { 2946 + copyfile_debug(1, "copyfile_unpack: calloc(1, %zu) returned NULL", hdrsize); 2947 + error = -1; 2948 + goto exit; 2949 + } else 2950 + endptr = (char*)buffer + hdrsize; 2951 + 2952 + bytes = pread(s->src_fd, buffer, hdrsize, 0); 2953 + 2954 + if (bytes < 0) 2955 + { 2956 + copyfile_debug(1, "pread returned: %zd", bytes); 2957 + error = -1; 2958 + goto exit; 2959 + } 2960 + if (bytes < hdrsize) 2961 + { 2962 + copyfile_debug(1, 2963 + "pread couldn't read entire header: %d of %d", 2964 + (int)bytes, (int)s->sb.st_size); 2965 + error = -1; 2966 + goto exit; 2967 + } 2968 + adhdr = (apple_double_header_t *)buffer; 2969 + 2970 + /* 2971 + * Check for Apple Double file. 2972 + */ 2973 + if ((size_t)bytes < sizeof(apple_double_header_t) - 2 || 2974 + SWAP32(adhdr->magic) != ADH_MAGIC || 2975 + SWAP32(adhdr->version) != ADH_VERSION || 2976 + SWAP16(adhdr->numEntries) != 2 || 2977 + SWAP32(adhdr->entries[0].type) != AD_FINDERINFO) 2978 + { 2979 + if (COPYFILE_VERBOSE & s->flags) 2980 + copyfile_warn("Not a valid Apple Double header"); 2981 + error = -1; 2982 + goto exit; 2983 + } 2984 + swap_adhdr(adhdr); 2985 + 2986 + /* 2987 + * Remove any extended attributes on the target. 2988 + */ 2989 + 2990 + if ((bytes = flistxattr(s->dst_fd, 0, 0, 0)) > 0) 2991 + { 2992 + char *namebuf, *name; 2993 + 2994 + if ((namebuf = (char*) malloc(bytes)) == NULL) 2995 + { 2996 + s->err = ENOMEM; 2997 + goto exit; 2998 + } 2999 + bytes = flistxattr(s->dst_fd, namebuf, bytes, 0); 3000 + 3001 + if (bytes > 0) 3002 + for (name = namebuf; name < namebuf + bytes; name += strlen(name) + 1) 3003 + (void)fremovexattr(s->dst_fd, name, 0); 3004 + 3005 + free(namebuf); 3006 + } 3007 + else if (bytes < 0) 3008 + { 3009 + if (errno != ENOTSUP && errno != EPERM) 3010 + goto exit; 3011 + } 3012 + 3013 + /* 3014 + * Extract the extended attributes. 3015 + * 3016 + * >>> WARNING <<< 3017 + * This assumes that the data is already in memory (not 3018 + * the case when there are lots of attributes or one of 3019 + * the attributes is very large. 3020 + */ 3021 + if (adhdr->entries[0].length > FINDERINFOSIZE) 3022 + { 3023 + attr_header_t *attrhdr; 3024 + attr_entry_t *entry; 3025 + int count; 3026 + int i; 3027 + 3028 + if ((size_t)hdrsize < sizeof(attr_header_t)) { 3029 + copyfile_warn("bad attribute header: %zu < %zu", hdrsize, sizeof(attr_header_t)); 3030 + error = -1; 3031 + goto exit; 3032 + } 3033 + 3034 + attrhdr = (attr_header_t *)buffer; 3035 + swap_attrhdr(attrhdr); 3036 + if (attrhdr->magic != ATTR_HDR_MAGIC) 3037 + { 3038 + if (COPYFILE_VERBOSE & s->flags) 3039 + copyfile_warn("bad attribute header"); 3040 + error = -1; 3041 + goto exit; 3042 + } 3043 + count = attrhdr->num_attrs; 3044 + entry = (attr_entry_t *)&attrhdr[1]; 3045 + 3046 + for (i = 0; i < count; i++) 3047 + { 3048 + /* 3049 + * First we do some simple sanity checking. 3050 + * +) See if entry is within the buffer's range; 3051 + * 3052 + * +) Check the attribute name length; if it's longer than the 3053 + * maximum, we truncate it down. (We could error out as well; 3054 + * I'm not sure which is the better way to go here.) 3055 + * 3056 + * +) If, given the name length, it goes beyond the end of 3057 + * the buffer, error out. 3058 + * 3059 + * +) If the last byte isn't a NUL, make it a NUL. (Since we 3060 + * truncated the name length above, we truncate the name here.) 3061 + * 3062 + * +) If entry->offset is so large that it causes dataptr to 3063 + * go beyond the end of the buffer -- or, worse, so large that 3064 + * it wraps around! -- we error out. 3065 + * 3066 + * +) If entry->length would cause the entry to go beyond the 3067 + * end of the buffer (or, worse, wrap around to before it), 3068 + * *or* if the length is larger than the hdrsize, we error out. 3069 + * (An explanation of that: what we're checking for there is 3070 + * the small range of values such that offset+length would cause 3071 + * it to go beyond endptr, and then wrap around past buffer. We 3072 + * care about this because we are passing entry->length down to 3073 + * fgetxattr() below, and an erroneously large value could cause 3074 + * problems there. By making sure that it's less than hdrsize, 3075 + * which has already been sanity-checked above, we're safe. 3076 + * That may mean that the check against < buffer is unnecessary.) 3077 + */ 3078 + if ((void*)entry >= endptr || (void*)entry < buffer) { 3079 + if (COPYFILE_VERBOSE & s->flags) 3080 + copyfile_warn("Incomplete or corrupt attribute entry"); 3081 + error = -1; 3082 + s->err = EINVAL; 3083 + goto exit; 3084 + } 3085 + 3086 + if (((char*)entry + sizeof(*entry)) > (char*)endptr) { 3087 + if (COPYFILE_VERBOSE & s->flags) 3088 + copyfile_warn("Incomplete or corrupt attribute entry"); 3089 + error = -1; 3090 + s->err = EINVAL; 3091 + goto exit; 3092 + } 3093 + 3094 + /* 3095 + * Endian swap the entry we're looking at. Previously 3096 + * we did this swap as part of swap_attrhdr, but that 3097 + * allowed a maliciously constructed file to overrun 3098 + * our allocation. Instead do the swap after we've verified 3099 + * the entry struct is within the buffer's range. 3100 + */ 3101 + swap_attrhdr_entry(entry); 3102 + 3103 + if (entry->namelen < 2) { 3104 + if (COPYFILE_VERBOSE & s->flags) 3105 + copyfile_warn("Corrupt attribute entry (only %d bytes)", entry->namelen); 3106 + error = -1; 3107 + s->err = EINVAL; 3108 + goto exit; 3109 + } 3110 + 3111 + if (entry->namelen > XATTR_MAXNAMELEN + 1) { 3112 + if (COPYFILE_VERBOSE & s->flags) 3113 + copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry->namelen); 3114 + error = -1; 3115 + s->err = EINVAL; 3116 + goto exit; 3117 + } 3118 + 3119 + if ((void*)(entry->name + entry->namelen) > endptr) { 3120 + if (COPYFILE_VERBOSE & s->flags) 3121 + copyfile_warn("Incomplete or corrupt attribute entry"); 3122 + error = -1; 3123 + s->err = EINVAL; 3124 + goto exit; 3125 + } 3126 + 3127 + /* Because namelen includes the NUL, we check one byte back */ 3128 + if (entry->name[entry->namelen-1] != 0) { 3129 + if (COPYFILE_VERBOSE & s->flags) 3130 + copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)"); 3131 + error = -1; 3132 + s->err = EINVAL; 3133 + goto exit; 3134 + } 3135 + 3136 + copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u", 3137 + entry->name, entry->length, entry->offset); 3138 + 3139 + #if 0 3140 + dataptr = (char *)attrhdr + entry->offset; 3141 + 3142 + if (dataptr > endptr || dataptr < buffer) { 3143 + copyfile_debug(1, "Entry %d overflows: offset = %u", i, entry->offset); 3144 + error = -1; 3145 + s->err = EINVAL; /* Invalid buffer */ 3146 + goto exit; 3147 + } 3148 + 3149 + if (((char*)dataptr + entry->length) > (char*)endptr || 3150 + (((char*)dataptr + entry->length) < (char*)buffer) || 3151 + (entry->length > (size_t)hdrsize)) { 3152 + if (COPYFILE_VERBOSE & s->flags) 3153 + copyfile_warn("Incomplete or corrupt attribute entry"); 3154 + copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u", 3155 + i, entry->offset, entry->length); 3156 + error = -1; 3157 + s->err = EINVAL; /* Invalid buffer */ 3158 + goto exit; 3159 + } 3160 + 3161 + #else 3162 + dataptr = malloc(entry->length); 3163 + if (dataptr == NULL) { 3164 + copyfile_debug(1, "no memory for %u bytes\n", entry->length); 3165 + error = -1; 3166 + s->err = ENOMEM; 3167 + goto exit; 3168 + } 3169 + if (pread(s->src_fd, dataptr, entry->length, entry->offset) != (ssize_t)entry->length) { 3170 + copyfile_debug(1, "failed to read %u bytes at offset %u\n", entry->length, entry->offset); 3171 + error = -1; 3172 + s->err = EINVAL; 3173 + goto exit; 3174 + } 3175 + #endif 3176 + 3177 + if (strcmp((char*)entry->name, XATTR_QUARANTINE_NAME) == 0) 3178 + { 3179 + qtn_file_t tqinfo = NULL; 3180 + 3181 + if (s->qinfo == NULL) 3182 + { 3183 + tqinfo = qtn_file_alloc(); 3184 + if (tqinfo) 3185 + { 3186 + int x; 3187 + if ((x = qtn_file_init_with_data(tqinfo, dataptr, entry->length)) != 0) 3188 + { 3189 + copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x)); 3190 + qtn_file_free(tqinfo); 3191 + tqinfo = NULL; 3192 + } 3193 + } 3194 + } 3195 + else 3196 + { 3197 + tqinfo = s->qinfo; 3198 + } 3199 + if (tqinfo) 3200 + { 3201 + int x; 3202 + x = qtn_file_apply_to_fd(tqinfo, s->dst_fd); 3203 + if (x != 0) { 3204 + copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x)); 3205 + if (s->statuscb) { 3206 + int rv; 3207 + s->xattr_name = (char*)XATTR_QUARANTINE_NAME; 3208 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 3209 + s->xattr_name = NULL; 3210 + if (rv == COPYFILE_QUIT) { 3211 + error = s->err = x < 0 ? ENOTSUP : errno; 3212 + goto exit; 3213 + } 3214 + } else { 3215 + error = s->err = x < 0 ? ENOTSUP : errno; 3216 + goto exit; 3217 + } 3218 + } 3219 + } 3220 + if (tqinfo && !s->qinfo) 3221 + { 3222 + qtn_file_free(tqinfo); 3223 + } 3224 + } 3225 + /* Look for ACL data */ 3226 + else if (strcmp((char*)entry->name, XATTR_SECURITY_NAME) == 0) 3227 + { 3228 + acl_t acl; 3229 + struct stat sb; 3230 + int retry = 1; 3231 + char *tcp = dataptr; 3232 + 3233 + if (entry->length == 0) { 3234 + /* Not sure how we got here, but we had one case 3235 + * where it was 0. In a normal EA, we can have a 0-byte 3236 + * payload. That means nothing in this case, so we'll 3237 + * simply skip the EA. 3238 + */ 3239 + error = 0; 3240 + goto acl_done; 3241 + } 3242 + /* 3243 + * acl_from_text() requires a NUL-terminated string. The ACL EA, 3244 + * however, may not be NUL-terminated. So in that case, we need to 3245 + * copy it to a +1 sized buffer, to ensure it's got a terminated string. 3246 + */ 3247 + if (tcp[entry->length - 1] != 0) { 3248 + char *tmpstr = malloc(entry->length + 1); 3249 + if (tmpstr == NULL) { 3250 + error = -1; 3251 + goto exit; 3252 + } 3253 + strlcpy(tmpstr, tcp, entry->length + 1); 3254 + acl = acl_from_text(tmpstr); 3255 + free(tmpstr); 3256 + } else { 3257 + acl = acl_from_text(tcp); 3258 + } 3259 + 3260 + if (acl != NULL) 3261 + { 3262 + filesec_t fsec_tmp; 3263 + 3264 + if ((fsec_tmp = filesec_init()) == NULL) 3265 + error = -1; 3266 + else if((error = fstatx_np(s->dst_fd, &sb, fsec_tmp)) < 0) 3267 + error = -1; 3268 + else if (filesec_set_property(fsec_tmp, FILESEC_ACL, &acl) < 0) 3269 + error = -1; 3270 + else { 3271 + while (fchmodx_np(s->dst_fd, fsec_tmp) < 0) 3272 + { 3273 + if (errno == ENOTSUP) 3274 + { 3275 + if (retry && !copyfile_unset_acl(s)) 3276 + { 3277 + retry = 0; 3278 + continue; 3279 + } 3280 + } 3281 + copyfile_warn("setting security information"); 3282 + error = -1; 3283 + break; 3284 + } 3285 + } 3286 + acl_free(acl); 3287 + filesec_free(fsec_tmp); 3288 + 3289 + acl_done: 3290 + if (error == -1) 3291 + goto exit; 3292 + } 3293 + } 3294 + /* And, finally, everything else */ 3295 + else 3296 + { 3297 + if (s->copyIntent || 3298 + xattr_preserve_for_intent((char*)entry->name, s->copyIntent) == 1) { 3299 + if (s->statuscb) { 3300 + int rv; 3301 + s->xattr_name = strdup((char*)entry->name); 3302 + s->totalCopied = 0; 3303 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx); 3304 + if (s->xattr_name) { 3305 + free(s->xattr_name); 3306 + s->xattr_name = NULL; 3307 + } 3308 + if (rv == COPYFILE_QUIT) { 3309 + s->err = ECANCELED; 3310 + error = -1; 3311 + goto exit; 3312 + } 3313 + } 3314 + if (fsetxattr(s->dst_fd, (char *)entry->name, dataptr, entry->length, 0, 0) == -1) { 3315 + if (COPYFILE_VERBOSE & s->flags) 3316 + copyfile_warn("error %d setting attribute %s", errno, entry->name); 3317 + if (s->statuscb) { 3318 + int rv; 3319 + 3320 + s->xattr_name = strdup((char*)entry->name); 3321 + rv = (s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 3322 + if (s->xattr_name) { 3323 + free(s->xattr_name); 3324 + s->xattr_name = NULL; 3325 + } 3326 + if (rv == COPYFILE_QUIT) { 3327 + error = -1; 3328 + goto exit; 3329 + } 3330 + } else { 3331 + error = -1; 3332 + goto exit; 3333 + } 3334 + } else if (s->statuscb) { 3335 + int rv; 3336 + s->xattr_name = strdup((char*)entry->name); 3337 + s->totalCopied = entry->length; 3338 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx); 3339 + if (s->xattr_name) { 3340 + free(s->xattr_name); 3341 + s->xattr_name = NULL; 3342 + } 3343 + if (rv == COPYFILE_QUIT) { 3344 + error = -1; 3345 + s->err = ECANCELED; 3346 + goto exit; 3347 + } 3348 + } 3349 + } 3350 + } 3351 + if (dataptr) { 3352 + free(dataptr); 3353 + dataptr = NULL; 3354 + } 3355 + entry = ATTR_NEXT(entry); 3356 + } 3357 + } 3358 + 3359 + /* 3360 + * Extract the Finder Info. 3361 + */ 3362 + if (adhdr->entries[0].offset > (hdrsize - sizeof(emptyfinfo))) { 3363 + error = -1; 3364 + goto exit; 3365 + } 3366 + 3367 + if (bcmp((u_int8_t*)buffer + adhdr->entries[0].offset, emptyfinfo, sizeof(emptyfinfo)) != 0) 3368 + { 3369 + uint16_t *fFlags; 3370 + uint8_t *newFinfo; 3371 + enum { kFinderInvisibleMask = 1 << 14 }; 3372 + 3373 + newFinfo = (u_int8_t*)buffer + adhdr->entries[0].offset; 3374 + fFlags = (uint16_t*)&newFinfo[8]; 3375 + copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME); 3376 + if (s->statuscb) { 3377 + int rv; 3378 + s->xattr_name = (char*)XATTR_FINDERINFO_NAME; 3379 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx); 3380 + s->xattr_name = NULL; 3381 + if (rv == COPYFILE_QUIT) { 3382 + error = -1; 3383 + s->err = ECANCELED; 3384 + goto exit; 3385 + } else if (rv == COPYFILE_SKIP) { 3386 + goto skip_fi; 3387 + } 3388 + } 3389 + error = fsetxattr(s->dst_fd, XATTR_FINDERINFO_NAME, (u_int8_t*)buffer + adhdr->entries[0].offset, sizeof(emptyfinfo), 0, 0); 3390 + if (error) { 3391 + if (s->statuscb) { 3392 + int rv; 3393 + s->xattr_name = (char *)XATTR_FINDERINFO_NAME; 3394 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 3395 + s->xattr_name = NULL; 3396 + if (rv == COPYFILE_QUIT) { 3397 + error = -1; 3398 + s->err = ECANCELED; 3399 + goto exit; 3400 + } 3401 + } 3402 + goto exit; 3403 + } else if (s->statuscb) { 3404 + int rv; 3405 + s->xattr_name = (char *)XATTR_FINDERINFO_NAME; 3406 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx); 3407 + s->xattr_name = NULL; 3408 + if (rv == COPYFILE_QUIT) { 3409 + error = -1; 3410 + s->err = ECANCELED; 3411 + goto exit; 3412 + } 3413 + } 3414 + if (SWAP16(*fFlags) & kFinderInvisibleMask) 3415 + s->internal_flags |= cfMakeFileInvisible; 3416 + } 3417 + skip_fi: 3418 + 3419 + /* 3420 + * Extract the Resource Fork. 3421 + */ 3422 + if (adhdr->entries[1].type == AD_RESOURCE && 3423 + adhdr->entries[1].length > 0) 3424 + { 3425 + void * rsrcforkdata = NULL; 3426 + size_t length; 3427 + off_t offset; 3428 + struct stat sb; 3429 + struct timeval tval[2]; 3430 + 3431 + length = adhdr->entries[1].length; 3432 + offset = adhdr->entries[1].offset; 3433 + rsrcforkdata = malloc(length); 3434 + 3435 + if (rsrcforkdata == NULL) { 3436 + copyfile_debug(1, "could not allocate %zu bytes for rsrcforkdata", 3437 + length); 3438 + error = -1; 3439 + goto bad; 3440 + } 3441 + 3442 + if (fstat(s->dst_fd, &sb) < 0) 3443 + { 3444 + copyfile_debug(1, "couldn't stat destination file"); 3445 + error = -1; 3446 + goto bad; 3447 + } 3448 + 3449 + bytes = pread(s->src_fd, rsrcforkdata, length, offset); 3450 + if (bytes < (ssize_t)length) 3451 + { 3452 + if (bytes == -1) 3453 + { 3454 + copyfile_debug(1, "couldn't read resource fork"); 3455 + } 3456 + else 3457 + { 3458 + copyfile_debug(1, 3459 + "couldn't read resource fork (only read %d bytes of %d)", 3460 + (int)bytes, (int)length); 3461 + } 3462 + error = -1; 3463 + goto bad; 3464 + } 3465 + if (s->statuscb) { 3466 + int rv; 3467 + s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME; 3468 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx); 3469 + s->xattr_name = NULL; 3470 + if (rv == COPYFILE_QUIT) { 3471 + error = -1; 3472 + s->err = ECANCELED; 3473 + if (rsrcforkdata) 3474 + free(rsrcforkdata); 3475 + goto exit; 3476 + } else if (rv == COPYFILE_SKIP) { 3477 + goto bad; 3478 + } 3479 + } 3480 + error = fsetxattr(s->dst_fd, XATTR_RESOURCEFORK_NAME, rsrcforkdata, bytes, 0, 0); 3481 + if (error) 3482 + { 3483 + /* 3484 + * For filesystems that do not natively support named attributes, 3485 + * the kernel creates an AppleDouble file that -- for compatabilty 3486 + * reasons -- has a resource fork containing nothing but a rsrcfork_header_t 3487 + * structure that says there are no resources. So, if fsetxattr has 3488 + * failed, and the resource fork is that empty structure, *and* the 3489 + * target file is a directory, then we do nothing with it. 3490 + */ 3491 + if ((bytes == sizeof(rsrcfork_header_t)) && 3492 + ((sb.st_mode & S_IFMT) == S_IFDIR) && 3493 + (memcmp(rsrcforkdata, &empty_rsrcfork_header, bytes) == 0)) { 3494 + copyfile_debug(2, "not setting empty resource fork on directory"); 3495 + error = errno = 0; 3496 + goto bad; 3497 + } 3498 + if (s->statuscb) { 3499 + int rv; 3500 + s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME; 3501 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 3502 + s->xattr_name = NULL; 3503 + if (rv == COPYFILE_CONTINUE) { 3504 + error = errno = 0; 3505 + goto bad; 3506 + } 3507 + } 3508 + copyfile_debug(1, "error %d setting resource fork attribute", error); 3509 + error = -1; 3510 + goto bad; 3511 + } else if (s->statuscb) { 3512 + int rv; 3513 + s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME; 3514 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx); 3515 + s->xattr_name = NULL; 3516 + if (rv == COPYFILE_QUIT) { 3517 + error = -1; 3518 + s->err = ECANCELED; 3519 + if (rsrcforkdata) 3520 + free(rsrcforkdata); 3521 + goto exit; 3522 + } 3523 + } 3524 + copyfile_debug(3, "extracting \"%s\" (%d bytes)", 3525 + XATTR_RESOURCEFORK_NAME, (int)length); 3526 + 3527 + if (!(s->flags & COPYFILE_STAT)) 3528 + { 3529 + tval[0].tv_sec = sb.st_atime; 3530 + tval[1].tv_sec = sb.st_mtime; 3531 + tval[0].tv_usec = tval[1].tv_usec = 0; 3532 + 3533 + if (futimes(s->dst_fd, tval)) 3534 + copyfile_warn("%s: set times", s->dst ? s->dst : "(null dst)"); 3535 + } 3536 + bad: 3537 + if (rsrcforkdata) 3538 + free(rsrcforkdata); 3539 + } 3540 + 3541 + if (COPYFILE_STAT & s->flags) 3542 + { 3543 + error = copyfile_stat(s); 3544 + } 3545 + exit: 3546 + if (buffer) free(buffer); 3547 + if (dataptr) free(dataptr); 3548 + return error; 3549 + } 3550 + 3551 + static int copyfile_pack_quarantine(copyfile_state_t s, void **buf, ssize_t *len) 3552 + { 3553 + int ret = 0; 3554 + char qbuf[QTN_SERIALIZED_DATA_MAX]; 3555 + size_t qlen = sizeof(qbuf); 3556 + 3557 + if (s->qinfo == NULL) 3558 + { 3559 + ret = -1; 3560 + goto done; 3561 + } 3562 + 3563 + if (qtn_file_to_data(s->qinfo, qbuf, &qlen) != 0) 3564 + { 3565 + ret = -1; 3566 + goto done; 3567 + } 3568 + 3569 + *buf = malloc(qlen); 3570 + if (*buf) 3571 + { 3572 + memcpy(*buf, qbuf, qlen); 3573 + *len = qlen; 3574 + } 3575 + done: 3576 + return ret; 3577 + } 3578 + 3579 + static int copyfile_pack_acl(copyfile_state_t s, void **buf, ssize_t *len) 3580 + { 3581 + int ret = 0; 3582 + acl_t acl = NULL; 3583 + char *acl_text; 3584 + 3585 + if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) < 0) 3586 + { 3587 + if (errno != ENOENT) 3588 + { 3589 + ret = -1; 3590 + if (COPYFILE_VERBOSE & s->flags) 3591 + copyfile_warn("getting acl"); 3592 + } 3593 + *len = 0; 3594 + goto exit; 3595 + } 3596 + 3597 + if ((acl_text = acl_to_text(acl, len)) != NULL) 3598 + { 3599 + /* 3600 + * acl_to_text() doesn't include the NUL at the endo 3601 + * in it's count (*len). It does, however, promise to 3602 + * return a valid C string, so we need to up the count 3603 + * by 1. 3604 + */ 3605 + *len = *len + 1; 3606 + *buf = malloc(*len); 3607 + if (*buf) 3608 + memcpy(*buf, acl_text, *len); 3609 + else 3610 + *len = 0; 3611 + acl_free(acl_text); 3612 + } 3613 + copyfile_debug(2, "copied acl (%ld) %p", *len, *buf); 3614 + exit: 3615 + if (acl) 3616 + acl_free(acl); 3617 + return ret; 3618 + } 3619 + 3620 + static int copyfile_pack_rsrcfork(copyfile_state_t s, attr_header_t *filehdr) 3621 + { 3622 + ssize_t datasize; 3623 + char *databuf = NULL; 3624 + int ret = 0; 3625 + 3626 + /* 3627 + * XXX 3628 + * do COPYFILE_COPY_XATTR here; no need to 3629 + * the work if we want to skip. 3630 + */ 3631 + 3632 + if (s->statuscb) 3633 + { 3634 + int rv; 3635 + 3636 + s->xattr_name = (char*)XATTR_RESOURCEFORK_NAME; 3637 + 3638 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx); 3639 + s->xattr_name = NULL; 3640 + if (rv == COPYFILE_SKIP) { 3641 + ret = 0; 3642 + goto done; 3643 + } 3644 + if (rv == COPYFILE_QUIT) { 3645 + ret = -1; 3646 + s->err = ECANCELED; 3647 + goto done; 3648 + } 3649 + } 3650 + /* Get the resource fork size */ 3651 + if ((datasize = fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, NULL, 0, 0, 0)) < 0) 3652 + { 3653 + if (COPYFILE_VERBOSE & s->flags) 3654 + copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME, errno); 3655 + return -1; 3656 + } 3657 + 3658 + if (datasize > INT_MAX) { 3659 + s->err = EINVAL; 3660 + ret = -1; 3661 + goto done; 3662 + } 3663 + 3664 + if (s->statuscb) { 3665 + int rv; 3666 + s->xattr_name = (char*)XATTR_RESOURCEFORK_NAME; 3667 + 3668 + s->totalCopied = 0; 3669 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx); 3670 + s->xattr_name = NULL; 3671 + if (rv == COPYFILE_QUIT) { 3672 + s->err = ECANCELED; 3673 + ret = -1; 3674 + goto done; 3675 + } 3676 + } 3677 + if ((databuf = malloc(datasize)) == NULL) 3678 + { 3679 + copyfile_warn("malloc"); 3680 + ret = -1; 3681 + goto done; 3682 + } 3683 + 3684 + if (fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, databuf, datasize, 0, 0) != datasize) 3685 + { 3686 + if (COPYFILE_VERBOSE & s->flags) 3687 + copyfile_warn("couldn't read entire resource fork"); 3688 + ret = -1; 3689 + goto done; 3690 + } 3691 + 3692 + /* Write the resource fork to disk. */ 3693 + if (pwrite(s->dst_fd, databuf, datasize, filehdr->appledouble.entries[1].offset) != datasize) 3694 + { 3695 + if (COPYFILE_VERBOSE & s->flags) 3696 + copyfile_warn("couldn't write resource fork"); 3697 + } 3698 + if (s->statuscb) 3699 + { 3700 + int rv; 3701 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx); 3702 + if (rv == COPYFILE_QUIT) { 3703 + ret = -1; 3704 + goto done; 3705 + } 3706 + } 3707 + copyfile_debug(3, "copied %zd bytes of \"%s\" data @ offset 0x%08x", 3708 + datasize, XATTR_RESOURCEFORK_NAME, filehdr->appledouble.entries[1].offset); 3709 + filehdr->appledouble.entries[1].length = (u_int32_t)datasize; 3710 + 3711 + done: 3712 + if (ret == -1 && s->statuscb) 3713 + { 3714 + int rv; 3715 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 3716 + if (rv == COPYFILE_CONTINUE) 3717 + ret = 0; 3718 + } 3719 + if (s->xattr_name) { 3720 + s->xattr_name = NULL; 3721 + } 3722 + if (databuf) 3723 + free(databuf); 3724 + 3725 + /* 3726 + * XXX 3727 + * Do status callback here 3728 + * If ret == -1, then error callback 3729 + */ 3730 + return ret; 3731 + } 3732 + 3733 + /* 3734 + * The opposite of copyfile_unpack(), obviously. 3735 + */ 3736 + static int copyfile_pack(copyfile_state_t s) 3737 + { 3738 + char *attrnamebuf = NULL, *endnamebuf; 3739 + void *databuf = NULL; 3740 + attr_header_t *filehdr, *endfilehdr; 3741 + attr_entry_t *entry; 3742 + ssize_t listsize = 0; 3743 + char *nameptr; 3744 + size_t namelen; 3745 + size_t entrylen; 3746 + ssize_t datasize; 3747 + size_t offset = 0; 3748 + int hasrsrcfork = 0; 3749 + int error = 0; 3750 + int seenq = 0; // Have we seen any quarantine info already? 3751 + 3752 + filehdr = (attr_header_t *) calloc(1, ATTR_MAX_HDR_SIZE); 3753 + 3754 + if (filehdr == NULL) { 3755 + error = -1; 3756 + goto exit; 3757 + } else { 3758 + endfilehdr = (attr_header_t*)(((char*)filehdr) + ATTR_MAX_HDR_SIZE); 3759 + } 3760 + 3761 + attrnamebuf = calloc(1, ATTR_MAX_HDR_SIZE); 3762 + if (attrnamebuf == NULL) { 3763 + error = -1; 3764 + goto exit; 3765 + } else { 3766 + endnamebuf = ((char*)attrnamebuf) + ATTR_MAX_HDR_SIZE; 3767 + } 3768 + 3769 + /* 3770 + * Fill in the Apple Double Header defaults. 3771 + */ 3772 + filehdr->appledouble.magic = ADH_MAGIC; 3773 + filehdr->appledouble.version = ADH_VERSION; 3774 + filehdr->appledouble.numEntries = 2; 3775 + filehdr->appledouble.entries[0].type = AD_FINDERINFO; 3776 + filehdr->appledouble.entries[0].offset = (u_int32_t)offsetof(apple_double_header_t, finfo); 3777 + filehdr->appledouble.entries[0].length = FINDERINFOSIZE; 3778 + filehdr->appledouble.entries[1].type = AD_RESOURCE; 3779 + filehdr->appledouble.entries[1].offset = (u_int32_t)offsetof(apple_double_header_t, pad); 3780 + filehdr->appledouble.entries[1].length = 0; 3781 + bcopy(ADH_MACOSX, filehdr->appledouble.filler, sizeof(filehdr->appledouble.filler)); 3782 + 3783 + /* 3784 + * Fill in the initial Attribute Header. 3785 + */ 3786 + filehdr->magic = ATTR_HDR_MAGIC; 3787 + filehdr->debug_tag = 0; 3788 + filehdr->data_start = (u_int32_t)sizeof(attr_header_t); 3789 + 3790 + /* 3791 + * Collect the attribute names. 3792 + */ 3793 + entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t)); 3794 + 3795 + /* 3796 + * Test if there are acls to copy 3797 + */ 3798 + if (COPYFILE_ACL & s->flags) 3799 + { 3800 + acl_t temp_acl = NULL; 3801 + if (filesec_get_property(s->fsec, FILESEC_ACL, &temp_acl) < 0) 3802 + { 3803 + copyfile_debug(2, "no acl entries found (errno = %d)", errno); 3804 + } else 3805 + { 3806 + offset = strlen(XATTR_SECURITY_NAME) + 1; 3807 + strcpy(attrnamebuf, XATTR_SECURITY_NAME); 3808 + endnamebuf = attrnamebuf + offset; 3809 + } 3810 + if (temp_acl) 3811 + acl_free(temp_acl); 3812 + } 3813 + 3814 + if (COPYFILE_XATTR & s->flags) 3815 + { 3816 + ssize_t left = ATTR_MAX_HDR_SIZE - offset; 3817 + if ((listsize = flistxattr(s->src_fd, attrnamebuf + offset, left, 0)) <= 0) 3818 + { 3819 + copyfile_debug(2, "no extended attributes found (%d)", errno); 3820 + } 3821 + if (listsize > left) 3822 + { 3823 + copyfile_debug(1, "extended attribute list too long"); 3824 + listsize = left; 3825 + } 3826 + 3827 + endnamebuf = attrnamebuf + offset + (listsize > 0 ? listsize : 0); 3828 + if (endnamebuf > (attrnamebuf + ATTR_MAX_HDR_SIZE)) { 3829 + error = -1; 3830 + goto exit; 3831 + } 3832 + 3833 + if (listsize > 0) 3834 + sort_xattrname_list(attrnamebuf, endnamebuf - attrnamebuf); 3835 + 3836 + for (nameptr = attrnamebuf; nameptr < endnamebuf; nameptr += namelen) 3837 + { 3838 + namelen = strlen(nameptr) + 1; 3839 + /* Skip over FinderInfo or Resource Fork names */ 3840 + if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0 || 3841 + strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0) { 3842 + continue; 3843 + } 3844 + if (strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0) { 3845 + seenq = 1; 3846 + } 3847 + 3848 + /* The system should prevent this from happening, but... */ 3849 + if (namelen > XATTR_MAXNAMELEN + 1) { 3850 + namelen = XATTR_MAXNAMELEN + 1; 3851 + } 3852 + if (s->copyIntent && 3853 + xattr_preserve_for_intent(nameptr, s->copyIntent) == 0) { 3854 + // Skip it 3855 + size_t amt = endnamebuf - (nameptr + namelen); 3856 + memmove(nameptr, nameptr + namelen, amt); 3857 + endnamebuf -= namelen; 3858 + /* Set namelen to 0 so continue doesn't miss names */ 3859 + namelen = 0; 3860 + continue; 3861 + } 3862 + 3863 + if (s->statuscb) { 3864 + int rv; 3865 + char eaname[namelen]; 3866 + bcopy(nameptr, eaname, namelen); 3867 + eaname[namelen - 1] = 0; // Just to be sure! 3868 + s->xattr_name = eaname; 3869 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx); 3870 + s->xattr_name = NULL; 3871 + if (rv == COPYFILE_QUIT) { 3872 + error = -1; 3873 + s->err = ECANCELED; 3874 + goto exit; 3875 + } else if (rv == COPYFILE_SKIP) { 3876 + size_t amt = endnamebuf - (nameptr + namelen); 3877 + memmove(nameptr, nameptr + namelen, amt); 3878 + endnamebuf -= namelen; 3879 + /* Set namelen to 0 so continue doesn't miss names */ 3880 + namelen = 0; 3881 + continue; 3882 + } 3883 + } 3884 + entry->namelen = namelen; 3885 + entry->flags = 0; 3886 + if (nameptr + namelen > endnamebuf) { 3887 + error = -1; 3888 + goto exit; 3889 + } 3890 + 3891 + bcopy(nameptr, &entry->name[0], namelen); 3892 + copyfile_debug(2, "copied name [%s]", entry->name); 3893 + 3894 + entrylen = ATTR_ENTRY_LENGTH(namelen); 3895 + entry = (attr_entry_t *)(((char *)entry) + entrylen); 3896 + 3897 + if ((void*)entry >= (void*)endfilehdr) { 3898 + error = -1; 3899 + goto exit; 3900 + } 3901 + 3902 + /* Update the attributes header. */ 3903 + filehdr->num_attrs++; 3904 + filehdr->data_start += (u_int32_t)entrylen; 3905 + } 3906 + } 3907 + 3908 + /* 3909 + * If we have any quarantine data, we always pack it. 3910 + * But if we've already got it in the EA list, don't put it in again. 3911 + */ 3912 + if (s->qinfo && !seenq) 3913 + { 3914 + ssize_t left = ATTR_MAX_HDR_SIZE - offset; 3915 + /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */ 3916 + offset += strlcpy(attrnamebuf + offset, XATTR_QUARANTINE_NAME, left) + 1; 3917 + } 3918 + 3919 + seenq = 0; 3920 + /* 3921 + * Collect the attribute data. 3922 + */ 3923 + entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t)); 3924 + 3925 + for (nameptr = attrnamebuf; nameptr < endnamebuf; nameptr += namelen + 1) 3926 + { 3927 + namelen = strlen(nameptr); 3928 + 3929 + if (strcmp(nameptr, XATTR_SECURITY_NAME) == 0) 3930 + copyfile_pack_acl(s, &databuf, &datasize); 3931 + else if (s->qinfo && strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0) 3932 + { 3933 + copyfile_pack_quarantine(s, &databuf, &datasize); 3934 + } 3935 + /* Check for Finder Info. */ 3936 + else if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0) 3937 + { 3938 + if (s->statuscb) 3939 + { 3940 + int rv; 3941 + s->xattr_name = (char*)XATTR_FINDERINFO_NAME; 3942 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx); 3943 + s->xattr_name = NULL; 3944 + if (rv == COPYFILE_QUIT) 3945 + { 3946 + s->xattr_name = NULL; 3947 + s->err = ECANCELED; 3948 + error = -1; 3949 + goto exit; 3950 + } 3951 + else if (rv == COPYFILE_SKIP) 3952 + { 3953 + s->xattr_name = NULL; 3954 + continue; 3955 + } 3956 + s->totalCopied = 0; 3957 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx); 3958 + s->xattr_name = NULL; 3959 + if (rv == COPYFILE_QUIT) 3960 + { 3961 + s->err = ECANCELED; 3962 + error = -1; 3963 + goto exit; 3964 + } 3965 + } 3966 + datasize = fgetxattr(s->src_fd, nameptr, (u_int8_t*)filehdr + filehdr->appledouble.entries[0].offset, 32, 0, 0); 3967 + if (datasize < 0) 3968 + { 3969 + if (s->statuscb) { 3970 + int rv; 3971 + s->xattr_name = strdup(nameptr); 3972 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 3973 + if (s->xattr_name) { 3974 + free(s->xattr_name); 3975 + s->xattr_name = NULL; 3976 + } 3977 + if (rv == COPYFILE_QUIT) { 3978 + error = -1; 3979 + goto exit; 3980 + } 3981 + } 3982 + if (COPYFILE_VERBOSE & s->flags) 3983 + copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno); 3984 + } else if (datasize != 32) 3985 + { 3986 + if (COPYFILE_VERBOSE & s->flags) 3987 + copyfile_warn("unexpected size (%ld) for \"%s\"", datasize, nameptr); 3988 + } else 3989 + { 3990 + if (COPYFILE_VERBOSE & s->flags) 3991 + copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x", 3992 + XATTR_FINDERINFO_NAME, filehdr->appledouble.entries[0].offset); 3993 + if (s->statuscb) { 3994 + int rv; 3995 + s->xattr_name = strdup(nameptr); 3996 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx); 3997 + if (s->xattr_name) { 3998 + free(s->xattr_name); 3999 + s->xattr_name = NULL; 4000 + } 4001 + if (rv == COPYFILE_QUIT) { 4002 + error = -1; 4003 + goto exit; 4004 + } 4005 + } 4006 + } 4007 + continue; /* finder info doesn't have an attribute entry */ 4008 + } 4009 + /* Check for Resource Fork. */ 4010 + else if (strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0) 4011 + { 4012 + hasrsrcfork = 1; 4013 + continue; 4014 + } else 4015 + { 4016 + /* Just a normal attribute. */ 4017 + if (s->statuscb) 4018 + { 4019 + int rv; 4020 + s->xattr_name = strdup(nameptr); 4021 + s->totalCopied = 0; 4022 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx); 4023 + if (s->xattr_name) { 4024 + free(s->xattr_name); 4025 + s->xattr_name = NULL; 4026 + } 4027 + /* 4028 + * Due to the nature of the packed file, we can't skip at this point. 4029 + */ 4030 + if (rv == COPYFILE_QUIT) 4031 + { 4032 + s->err = ECANCELED; 4033 + error = -1; 4034 + goto exit; 4035 + } 4036 + } 4037 + datasize = fgetxattr(s->src_fd, nameptr, NULL, 0, 0, 0); 4038 + if (datasize == 0) 4039 + goto next; 4040 + if (datasize < 0) 4041 + { 4042 + if (COPYFILE_VERBOSE & s->flags) 4043 + copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno); 4044 + if (s->statuscb) 4045 + { 4046 + int rv; 4047 + s->xattr_name = strdup(nameptr); 4048 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 4049 + if (s->xattr_name) { 4050 + free(s->xattr_name); 4051 + s->xattr_name = NULL; 4052 + } 4053 + if (rv == COPYFILE_QUIT) 4054 + { 4055 + s->err = ECANCELED; 4056 + error = -1; 4057 + goto exit; 4058 + } 4059 + } 4060 + goto next; 4061 + } 4062 + if (datasize > XATTR_MAXATTRLEN) 4063 + { 4064 + if (COPYFILE_VERBOSE & s->flags) 4065 + copyfile_warn("skipping attr \"%s\" (too big)", nameptr); 4066 + goto next; 4067 + } 4068 + databuf = malloc(datasize); 4069 + if (databuf == NULL) { 4070 + error = -1; 4071 + continue; 4072 + } 4073 + datasize = fgetxattr(s->src_fd, nameptr, databuf, datasize, 0, 0); 4074 + if (s->statuscb) { 4075 + int rv; 4076 + s->xattr_name = strdup(nameptr); 4077 + rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx); 4078 + if (s->xattr_name) { 4079 + free(s->xattr_name); 4080 + s->xattr_name = NULL; 4081 + } 4082 + if (rv == COPYFILE_QUIT) { 4083 + s->err = ECANCELED; 4084 + error = -1; 4085 + goto exit; 4086 + } 4087 + } 4088 + } 4089 + 4090 + entry->length = (u_int32_t)datasize; 4091 + entry->offset = filehdr->data_start + filehdr->data_length; 4092 + 4093 + filehdr->data_length += (u_int32_t)datasize; 4094 + #if 0 4095 + /* 4096 + * >>> WARNING <<< 4097 + * This assumes that the data is fits in memory (not 4098 + * the case when there are lots of attributes or one of 4099 + * the attributes is very large. 4100 + */ 4101 + if (entry->offset > ATTR_MAX_SIZE || 4102 + (entry->offset + datasize > ATTR_MAX_SIZE)) { 4103 + error = 1; 4104 + } else { 4105 + bcopy(databuf, (char*)filehdr + entry->offset, datasize); 4106 + } 4107 + #else 4108 + if (pwrite(s->dst_fd, databuf, datasize, entry->offset) != datasize) { 4109 + error = 1; 4110 + } 4111 + #endif 4112 + free(databuf); 4113 + 4114 + copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize, nameptr, entry->offset); 4115 + next: 4116 + /* bump to next entry */ 4117 + entrylen = ATTR_ENTRY_LENGTH(entry->namelen); 4118 + entry = (attr_entry_t *)((char *)entry + entrylen); 4119 + } 4120 + 4121 + /* Now we know where the resource fork data starts. */ 4122 + filehdr->appledouble.entries[1].offset = (filehdr->data_start + filehdr->data_length); 4123 + 4124 + /* We also know the size of the "Finder Info entry. */ 4125 + filehdr->appledouble.entries[0].length = 4126 + filehdr->appledouble.entries[1].offset - filehdr->appledouble.entries[0].offset; 4127 + 4128 + filehdr->total_size = filehdr->appledouble.entries[1].offset; 4129 + 4130 + /* Copy Resource Fork. */ 4131 + if (hasrsrcfork && (error = copyfile_pack_rsrcfork(s, filehdr))) 4132 + goto exit; 4133 + 4134 + /* Write the header to disk. */ 4135 + datasize = filehdr->data_start; 4136 + 4137 + swap_adhdr(&filehdr->appledouble); 4138 + swap_attrhdr(filehdr); 4139 + swap_attrhdr_entries(filehdr); 4140 + 4141 + if (pwrite(s->dst_fd, filehdr, datasize, 0) != datasize) 4142 + { 4143 + if (COPYFILE_VERBOSE & s->flags) 4144 + copyfile_warn("couldn't write file header"); 4145 + error = -1; 4146 + goto exit; 4147 + } 4148 + exit: 4149 + if (filehdr) free(filehdr); 4150 + if (attrnamebuf) free(attrnamebuf); 4151 + 4152 + if (error) 4153 + return error; 4154 + else 4155 + return copyfile_stat(s); 4156 + }
+123
src/copyfile/copyfile.h
··· 1 + /* 2 + * Copyright (c) 2004-2010 Apple, Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + #ifndef _COPYFILE_H_ /* version 0.1 */ 24 + #define _COPYFILE_H_ 25 + 26 + /* 27 + * This API facilitates the copying of files and their associated 28 + * metadata. There are several open source projects that need 29 + * modifications to support preserving extended attributes and ACLs 30 + * and this API collapses several hundred lines of modifications into 31 + * one or two calls. 32 + */ 33 + 34 + /* private */ 35 + #include <sys/cdefs.h> 36 + #include <stdint.h> 37 + 38 + __BEGIN_DECLS 39 + struct _copyfile_state; 40 + typedef struct _copyfile_state * copyfile_state_t; 41 + typedef uint32_t copyfile_flags_t; 42 + 43 + /* public */ 44 + 45 + /* receives: 46 + * from path to source file system object 47 + * to path to destination file system object 48 + * state opaque blob for future extensibility 49 + * Must be NULL in current implementation 50 + * flags (described below) 51 + * returns: 52 + * int negative for error 53 + */ 54 + 55 + int copyfile(const char *from, const char *to, copyfile_state_t state, copyfile_flags_t flags); 56 + int fcopyfile(int from_fd, int to_fd, copyfile_state_t, copyfile_flags_t flags); 57 + 58 + int copyfile_state_free(copyfile_state_t); 59 + copyfile_state_t copyfile_state_alloc(void); 60 + 61 + 62 + int copyfile_state_get(copyfile_state_t s, uint32_t flag, void * dst); 63 + int copyfile_state_set(copyfile_state_t s, uint32_t flag, const void * src); 64 + 65 + typedef int (*copyfile_callback_t)(int, int, copyfile_state_t, const char *, const char *, void *); 66 + 67 + #define COPYFILE_STATE_SRC_FD 1 68 + #define COPYFILE_STATE_SRC_FILENAME 2 69 + #define COPYFILE_STATE_DST_FD 3 70 + #define COPYFILE_STATE_DST_FILENAME 4 71 + #define COPYFILE_STATE_QUARANTINE 5 72 + #define COPYFILE_STATE_STATUS_CB 6 73 + #define COPYFILE_STATE_STATUS_CTX 7 74 + #define COPYFILE_STATE_COPIED 8 75 + #define COPYFILE_STATE_XATTRNAME 9 76 + 77 + 78 + #define COPYFILE_DISABLE_VAR "COPYFILE_DISABLE" 79 + 80 + /* flags for copyfile */ 81 + 82 + #define COPYFILE_ACL (1<<0) 83 + #define COPYFILE_STAT (1<<1) 84 + #define COPYFILE_XATTR (1<<2) 85 + #define COPYFILE_DATA (1<<3) 86 + 87 + #define COPYFILE_SECURITY (COPYFILE_STAT | COPYFILE_ACL) 88 + #define COPYFILE_METADATA (COPYFILE_SECURITY | COPYFILE_XATTR) 89 + #define COPYFILE_ALL (COPYFILE_METADATA | COPYFILE_DATA) 90 + 91 + #define COPYFILE_RECURSIVE (1<<15) /* Descend into hierarchies */ 92 + #define COPYFILE_CHECK (1<<16) /* return flags for xattr or acls if set */ 93 + #define COPYFILE_EXCL (1<<17) /* fail if destination exists */ 94 + #define COPYFILE_NOFOLLOW_SRC (1<<18) /* don't follow if source is a symlink */ 95 + #define COPYFILE_NOFOLLOW_DST (1<<19) /* don't follow if dst is a symlink */ 96 + #define COPYFILE_MOVE (1<<20) /* unlink src after copy */ 97 + #define COPYFILE_UNLINK (1<<21) /* unlink dst before copy */ 98 + #define COPYFILE_NOFOLLOW (COPYFILE_NOFOLLOW_SRC | COPYFILE_NOFOLLOW_DST) 99 + 100 + #define COPYFILE_PACK (1<<22) 101 + #define COPYFILE_UNPACK (1<<23) 102 + 103 + #define COPYFILE_VERBOSE (1<<30) 104 + 105 + #define COPYFILE_RECURSE_ERROR 0 106 + #define COPYFILE_RECURSE_FILE 1 107 + #define COPYFILE_RECURSE_DIR 2 108 + #define COPYFILE_RECURSE_DIR_CLEANUP 3 109 + #define COPYFILE_COPY_DATA 4 110 + #define COPYFILE_COPY_XATTR 5 111 + 112 + #define COPYFILE_START 1 113 + #define COPYFILE_FINISH 2 114 + #define COPYFILE_ERR 3 115 + #define COPYFILE_PROGRESS 4 116 + 117 + #define COPYFILE_CONTINUE 0 118 + #define COPYFILE_SKIP 1 119 + #define COPYFILE_QUIT 2 120 + 121 + __END_DECLS 122 + 123 + #endif /* _COPYFILE_H_ */
+38
src/copyfile/copyfile_private.h
··· 1 + /* 2 + * Copyright (c) 2013 Apple, Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #ifndef _COPYFILE_PRIVATE_H 25 + # define _COPYFILE_PRIVATE_H 26 + 27 + /* 28 + * Set (or get) the intent type; see xattr_properties.h for details. 29 + * This command uses a pointer to CopyOperationIntent_t as the parameter. 30 + */ 31 + # define COPYFILE_STATE_INTENT 256 32 + 33 + /* 34 + * File flags that are not preserved when copying stat information. 35 + */ 36 + #define COPYFILE_OMIT_FLAGS (UF_TRACKED | SF_RESTRICTED) 37 + 38 + #endif /* _COPYFILE_PRIVATE_H */
+340
src/copyfile/xattr_flags.c
··· 1 + /* 2 + * Copyright (c) 2013 Apple, Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #include <stdio.h> 25 + #include <stdlib.h> 26 + #include <string.h> 27 + #include <unistd.h> 28 + #include <err.h> 29 + #include <errno.h> 30 + #include <sys/types.h> 31 + #include <sys/xattr.h> 32 + #include <dispatch/dispatch.h> 33 + #include <xpc/private.h> 34 + 35 + #include <xattr_flags.h> 36 + 37 + #define FLAG_DELIM_CHAR '#' 38 + #define FLAG_DELIM_STR "#" 39 + 40 + /* 41 + * Some default propeteries for EAs we know about internally. 42 + */ 43 + struct defaultList { 44 + const char *eaName; 45 + const char *propList; 46 + int flags; // See below 47 + }; 48 + 49 + #define propFlagsPrefix 0x0001 // The name is a prefix, so only look at that part 50 + 51 + static const struct defaultList *defaultPropertyTable = NULL; 52 + 53 + static const struct defaultList 54 + defaultUnboxedPropertyTable[] = { 55 + { "com.apple.quarantine", "PCS", 0 }, // not public 56 + { "com.apple.TextEncoding", "CS", 0 }, // Content-dependent, public 57 + { "com.apple.metadata:", "PS", propFlagsPrefix }, // Don't export, keep for copy & safe save 58 + { "com.apple.security.", "S", propFlagsPrefix }, 59 + { XATTR_RESOURCEFORK_NAME, "PCS", 0 }, // Don't keep for safe save 60 + { XATTR_FINDERINFO_NAME, "PCS", 0 }, // Same as ResourceFork 61 + { 0, 0, 0 }, 62 + }; 63 + 64 + static const struct defaultList 65 + defaultSandboxedPropertyTable[] = { 66 + { "com.apple.quarantine", "PCS", 0 }, // not public 67 + { "com.apple.TextEncoding", "CS", 0 }, // Content-dependent, public 68 + { "com.apple.metadata:", "PS", propFlagsPrefix }, // Don't export, keep for copy & safe save 69 + { "com.apple.security.", "N", propFlagsPrefix }, 70 + { XATTR_RESOURCEFORK_NAME, "PCS", 0 }, // Don't keep for safe save 71 + { XATTR_FINDERINFO_NAME, "PCS", 0 }, // Same as ResourceFork 72 + { 0, 0, 0 }, 73 + }; 74 + 75 + /* 76 + * The property lists on an EA are set by having a suffix character, 77 + * and then a list of characters. In general, we're choosing upper-case 78 + * to indicate the property is set, and lower-case to indicate it's to be 79 + * cleared. 80 + */ 81 + struct propertyListMapping { 82 + char enable; // Character to enable 83 + char disable; // Character to disable -- usually lower-case of enable 84 + xattr_operation_intent_t value; 85 + }; 86 + static const struct propertyListMapping 87 + PropertyListMapTable[] = { 88 + { 'C', 'c', XATTR_FLAG_CONTENT_DEPENDENT }, 89 + { 'P', 'p', XATTR_FLAG_NO_EXPORT }, 90 + { 'N', 'n', XATTR_FLAG_NEVER_PRESERVE }, 91 + { 'S', 's', XATTR_FLAG_SYNCABLE }, 92 + { 0, 0, 0 }, 93 + }; 94 + 95 + /* 96 + * Given a converted property list (that is, converted to the 97 + * xattr_operation_intent_t type), and an intent, determine if 98 + * it should be preserved or not. 99 + * 100 + * I've chosen to use a block instead of a simple mask on the belief 101 + * that the question may be moderately complex. If it ends up not being 102 + * so, then this can simply be turned into a mask of which bits to check 103 + * as being exclusionary. 104 + */ 105 + static const struct divineIntent { 106 + xattr_operation_intent_t intent; 107 + int (^checker)(xattr_flags_t); 108 + } intentTable[] = { 109 + { XATTR_OPERATION_INTENT_COPY, ^(xattr_flags_t flags) { 110 + if (flags & XATTR_FLAG_NEVER_PRESERVE) 111 + return 0; 112 + return 1; 113 + } }, 114 + { XATTR_OPERATION_INTENT_SAVE, ^(xattr_flags_t flags) { 115 + if (flags & (XATTR_FLAG_CONTENT_DEPENDENT | XATTR_FLAG_NEVER_PRESERVE)) 116 + return 0; 117 + return 1; 118 + } }, 119 + { XATTR_OPERATION_INTENT_SHARE, ^(xattr_flags_t flags) { 120 + if ((flags & (XATTR_FLAG_NO_EXPORT | XATTR_FLAG_NEVER_PRESERVE)) != 0) 121 + return 0; 122 + return 1; 123 + } }, 124 + { XATTR_OPERATION_INTENT_SYNC, ^(xattr_flags_t flags) { 125 + return (flags & (XATTR_FLAG_SYNCABLE | XATTR_FLAG_NEVER_PRESERVE)) == XATTR_FLAG_SYNCABLE; 126 + } }, 127 + { 0, 0 }, 128 + }; 129 + 130 + 131 + /* 132 + * If an EA name is in the default list, find it, and return the property 133 + * list string for it. 134 + */ 135 + static const char * 136 + nameInDefaultList(const char *eaname) 137 + { 138 + const struct defaultList *retval; 139 + static dispatch_once_t onceToken; 140 + 141 + dispatch_once(&onceToken, ^{ 142 + if (_xpc_runtime_is_app_sandboxed()) { 143 + defaultPropertyTable = defaultSandboxedPropertyTable; 144 + } else { 145 + defaultPropertyTable = defaultUnboxedPropertyTable; 146 + } 147 + }); 148 + 149 + for (retval = defaultPropertyTable; retval->eaName; retval++) { 150 + if ((retval->flags & propFlagsPrefix) != 0 && 151 + strncmp(retval->eaName, eaname, strlen(retval->eaName)) == 0) 152 + return retval->propList; 153 + if (strcmp(retval->eaName, eaname) == 0) 154 + return retval->propList; 155 + } 156 + return NULL; 157 + } 158 + 159 + /* 160 + * Given an EA name, see if it has a property list in it, and 161 + * return a pointer to it. All this is doing is looking for 162 + * the delimiter, and returning the string after that. Returns 163 + * NULL if the delimiter isn't found. Note that an empty string 164 + * is a valid property list, as far as we're concerned. 165 + */ 166 + static const char * 167 + findPropertyList(const char *eaname) 168 + { 169 + const char *ptr = strrchr(eaname, '#'); 170 + if (ptr) 171 + return ptr+1; 172 + return NULL; 173 + } 174 + 175 + /* 176 + * Convert a property list string (e.g., "pCd") into a 177 + * xattr_operation_intent_t type. 178 + */ 179 + static xattr_operation_intent_t 180 + stringToProperties(const char *proplist) 181 + { 182 + xattr_operation_intent_t retval = 0; 183 + const char *ptr; 184 + 185 + // A switch would be more efficient, but less generic. 186 + for (ptr = proplist; *ptr; ptr++) { 187 + const struct propertyListMapping *mapPtr; 188 + for (mapPtr = PropertyListMapTable; mapPtr->enable; mapPtr++) { 189 + if (*ptr == mapPtr->enable) { 190 + retval |= mapPtr->value; 191 + } else if (*ptr == mapPtr->disable) { 192 + retval &= ~mapPtr->value; 193 + } 194 + } 195 + } 196 + return retval; 197 + } 198 + 199 + /* 200 + * Given an EA name (e.g., "com.apple.lfs.hfs.test"), and a 201 + * xattr_operation_intent_t value (it's currently an integral value, so 202 + * just a bitmask), cycle through the list of known properties, and return 203 + * a string with the EA name, and the property list appended. E.g., we 204 + * might return "com.apple.lfs.hfs.test#pD". 205 + * 206 + * The tricky part of this funciton is that it will not append any letters 207 + * if the value is only the default properites. In that case, it will copy 208 + * the EA name, and return that. 209 + * 210 + * It returns NULL if there was an error. The two errors right now are 211 + * no memory (strdup failed), in which case it will set errno to ENOMEM; and 212 + * the resulting EA name is longer than XATTR_MAXNAMELEN, in which case it 213 + * sets errno to ENAMETOOLONG. 214 + * 215 + * (Note that it also uses ENAMETOOLONG if the buffer it's trying to set 216 + * gets too large. I honestly can't see how that would happen, but it's there 217 + * for sanity checking. That would require having more than 64 bits to use.) 218 + */ 219 + char * 220 + xattr_name_with_flags(const char *orig, xattr_flags_t propList) 221 + { 222 + char *retval = NULL; 223 + char suffix[66] = { 0 }; // 66: uint64_t for property types, plus '#', plus NUL 224 + char *cur = suffix; 225 + const struct propertyListMapping *mapPtr; 226 + 227 + *cur++ = '#'; 228 + for (mapPtr = PropertyListMapTable; mapPtr->enable; mapPtr++) { 229 + if ((propList & mapPtr->value) != 0) { 230 + *cur++ = mapPtr->enable; 231 + } 232 + if (cur >= (suffix + sizeof(suffix))) { 233 + errno = ENAMETOOLONG; 234 + return NULL; 235 + } 236 + 237 + } 238 + 239 + 240 + if (cur == suffix + 1) { 241 + // No changes made 242 + retval = strdup(orig); 243 + if (retval == NULL) 244 + errno = ENOMEM; 245 + } else { 246 + const char *defaultEntry = NULL; 247 + if ((defaultEntry = nameInDefaultList(orig)) != NULL && 248 + strcmp(defaultEntry, suffix + 1) == 0) { 249 + // Just use the name passed in 250 + retval = strdup(orig); 251 + } else { 252 + asprintf(&retval, "%s%s", orig, suffix); 253 + } 254 + if (retval == NULL) { 255 + errno = ENOMEM; 256 + } else { 257 + if (strlen(retval) > XATTR_MAXNAMELEN) { 258 + free(retval); 259 + retval = NULL; 260 + errno = ENAMETOOLONG; 261 + } 262 + } 263 + } 264 + return retval; 265 + } 266 + 267 + char * 268 + xattr_name_without_flags(const char *eaname) 269 + { 270 + char *retval = NULL; 271 + char *tmp; 272 + 273 + if ((tmp = strrchr(eaname, FLAG_DELIM_CHAR)) == NULL) { 274 + retval = strdup(eaname); 275 + } else { 276 + retval = calloc(tmp - eaname + 1, 1); 277 + if (retval) { 278 + strlcpy(retval, eaname, tmp - eaname + 1); 279 + } 280 + } 281 + if (retval == NULL) { 282 + errno = ENOMEM; 283 + } 284 + return retval; 285 + } 286 + 287 + int 288 + xattr_intent_with_flags(xattr_operation_intent_t intent, xattr_flags_t flags) 289 + { 290 + const struct divineIntent *ip; 291 + 292 + for (ip = intentTable; ip->intent; ip++) { 293 + if (ip->intent == intent) { 294 + return ip->checker(flags); 295 + } 296 + } 297 + if ((flags & XATTR_FLAG_NEVER_PRESERVE) != 0) 298 + return 0; // Special case, don't try to copy this one 299 + 300 + return 1; // Default 301 + } 302 + 303 + xattr_flags_t 304 + xattr_flags_from_name(const char *eaname) 305 + { 306 + xattr_flags_t retval = 0; 307 + const char *propList; 308 + 309 + propList = findPropertyList(eaname); 310 + if (propList == NULL) { 311 + propList = nameInDefaultList(eaname); 312 + } 313 + if (propList != NULL) { 314 + retval = stringToProperties(propList); 315 + } 316 + 317 + return retval; 318 + } 319 + 320 + /* 321 + * Indicate whether an EA should be preserved, when using the 322 + * given intent. 323 + * 324 + * This returns 0 if it should not be preserved, and 1 if it should. 325 + * 326 + * It simply looks through the tables we have above, and compares the 327 + * xattr_operation_intent_t for the EA with the intent. If the 328 + * EA doesn't have any properties, and it's not on the default list, the 329 + * default is to preserve it. 330 + */ 331 + 332 + int 333 + xattr_preserve_for_intent(const char *eaname, xattr_operation_intent_t intent) 334 + { 335 + xattr_flags_t flags = xattr_flags_from_name(eaname); 336 + 337 + return xattr_intent_with_flags(intent, flags); 338 + } 339 + 340 + #include "xattr_properties.h"
+149
src/copyfile/xattr_flags.h
··· 1 + /* 2 + * Copyright (c) 2013 Apple, Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #ifndef _XATTR_FLAGS_H 25 + #define _XATTR_FLAGS_H 26 + 27 + #include <stdint.h> 28 + 29 + #include <sys/cdefs.h> 30 + #include <Availability.h> 31 + 32 + __BEGIN_DECLS 33 + 34 + /* 35 + * xattr_operation_intent_t is used to declare what the intent of the copy is. 36 + * Not a bit-field (for now, at least). 37 + * 38 + * XATTR_OPERATION_INTENT_COPY indicates that the EA is attached to an object 39 + * that is simply being copied. E.g., cp src dst 40 + * 41 + * XATTR_OPERATION_INTENT_SAVE indicates that the EA is attached to an object 42 + * being saved; as in a "safe save," the destination is being replaced by 43 + * the source, so the question is whether the EA should be applied to the 44 + * destination, or generated anew. 45 + * 46 + * XATTR_OPERATION_INTENT_SHARE indicates that the EA is attached to an object that 47 + * is being given out to other people. For example, saving to a public folder, 48 + * or attaching to an email message. 49 + * 50 + * XATTR_OPERATION_INTENT_SYNC indicates that the EA is attached to an object that 51 + * is being synced to other storages for the same user. For example synced to 52 + * iCloud. 53 + */ 54 + 55 + #define XATTR_OPERATION_INTENT_COPY 1 56 + #define XATTR_OPERATION_INTENT_SAVE 2 57 + #define XATTR_OPERATION_INTENT_SHARE 3 58 + #define XATTR_OPERATION_INTENT_SYNC 4 59 + 60 + typedef unsigned int xattr_operation_intent_t; 61 + 62 + typedef uint64_t xattr_flags_t; 63 + 64 + /* 65 + * Various properties used to determine how to handle the xattr during 66 + * copying. The intent is that the default is reasonable for most xattrs. 67 + */ 68 + 69 + /* 70 + * XATTR_FLAG_NO_EXPORT 71 + * Declare that the extended property should not be exported; this is 72 + * deliberately a bit vague, but this is used by XATTR_OPERATION_INTENT_SHARE 73 + * to indicate not to preserve the xattr. 74 + */ 75 + #define XATTR_FLAG_NO_EXPORT ((xattr_flags_t)0x0001) 76 + 77 + /* 78 + * XATTR_FLAG_CONTENT_DEPENDENT 79 + * Declares the extended attribute to be tied to the contents of the file (or 80 + * vice versa), such that it should be re-created when the contents of the 81 + * file change. Examples might include cryptographic keys, checksums, saved 82 + * position or search information, and text encoding. 83 + * 84 + * This property causes the EA to be preserved for copy and share, but not for 85 + * safe save. (In a safe save, the EA exists on the original, and will not 86 + * be copied to the new version.) 87 + */ 88 + #define XATTR_FLAG_CONTENT_DEPENDENT ((xattr_flags_t)0x0002) 89 + 90 + /* 91 + * XATTR_FLAG_NEVER_PRESERVE 92 + * Declares that the extended attribute is never to be copied, for any 93 + * intention type. 94 + */ 95 + #define XATTR_FLAG_NEVER_PRESERVE ((xattr_flags_t)0x0004) 96 + 97 + /* 98 + * XATTR_FLAG_SYNCABLE 99 + * Declares that the extended attribute is to be synced, used by the 100 + * XATTR_OPERATION_ITENT_SYNC intention. Syncing tends to want to minimize the 101 + * amount of metadata synced around, hence the default behavior is for the EA 102 + * NOT to be synced, even if it would else be preserved for the 103 + * XATTR_OPERATION_ITENT_COPY intention. 104 + */ 105 + #define XATTR_FLAG_SYNCABLE ((xattr_flags_t)0x0008) 106 + 107 + /* Given a named extended attribute, and a copy intent, should the EA be preserved? */ 108 + extern int xattr_preserve_for_intent(const char *, xattr_operation_intent_t) __OSX_AVAILABLE_STARTING( __MAC_10_10, __IPHONE_8_0); 109 + 110 + /* 111 + * Given an extended attribute name, and a set of properties, return an 112 + * allocated C string with the name. This will return NULL on error; 113 + * errno may be set to ENOMEM if the new name cannot be allocated, or 114 + * ENAMETOOLONG if the new name is longer than the maximum for EAs (127 UTF8 115 + * characters). The caller must deallocate the return value otherwise. 116 + * 117 + * If no properties are set, it returns a copy of the EA name. 118 + * 119 + * If the EA name is in the internal list, and the properties are the same as 120 + * defined there, then it will also return an unmodified copy of the EA name. 121 + */ 122 + extern char *xattr_name_with_flags(const char *, xattr_flags_t) __OSX_AVAILABLE_STARTING( __MAC_10_10, __IPHONE_8_0); 123 + 124 + /* 125 + * Given an extended attribute name, which may or may not have properties encoded 126 + * as a suffix, return just the name of the attribute. E.g., com.example.mine#P 127 + * would return "com.example.mine". The return value will be NULL on error; 128 + * errno will be set to ENOMEM if it cannot be allocated. The caller must deallocate 129 + * the return value. 130 + */ 131 + extern char *xattr_name_without_flags(const char *) __OSX_AVAILABLE_STARTING( __MAC_10_10, __IPHONE_8_0); 132 + 133 + /* 134 + * Given an EA name, return the properties. If the name is in the internal list, 135 + * those properties will be returned. Unknown property encodings are ignored. 136 + */ 137 + extern xattr_flags_t xattr_flags_from_name(const char *) __OSX_AVAILABLE_STARTING( __MAC_10_10, __IPHONE_8_0); 138 + 139 + /* 140 + * Given an xattr_operation_intent_t and an xattr_flags_t, return whether it should 141 + * be preserved. The default (in case either flags or intent is 0, or unknown 142 + * values) is to return 1; it only returns 0 if the flags and intent indicate it 143 + * should not be preserved. 144 + */ 145 + extern int xattr_intent_with_flags(xattr_operation_intent_t, xattr_flags_t) __OSX_AVAILABLE_STARTING( __MAC_10_10, __IPHONE_8_0); 146 + 147 + __END_DECLS 148 + 149 + #endif /* _XATTR_FLAGS_H */
+123
src/copyfile/xattr_name_with_flags.3
··· 1 + .\" 2 + .\" Copyright (c) 2013 Apple Computer, Inc. All rights reserved. 3 + .\" 4 + .Dd October 7, 2013 5 + .Dt XATTR_NAME_WITH_FLAGS 3 6 + .Os 7 + .Sh NAME 8 + .Nm xattr_preserve_for_intent , xattr_name_with_flags , xattr_name_without_flags , 9 + .Nm xattr_flags_from_name , xattr_intent_with_flags 10 + .Sh LIBRARY 11 + .Lb libc 12 + .Sh SYNOPSIS 13 + .In xattr_properties.h 14 + .Ft int 15 + .Fn xattr_preserve_for_intent "const char *" "xattr_operation_intent_t" 16 + .Ft char * 17 + .Fn xattr_name_with_flags "const char *" "xattr_flags_t" 18 + .Ft char * 19 + .Fn xattr_name_without_flags "const char *" 20 + .Ft xattr_flags_t 21 + .Fn xattr_flags_from_name "const char *" 22 + .Ft int 23 + .Fn xattr_intent_with_flags "xattr_operation_intent_t" "xattr_flags_t" 24 + .Sh DESCRIPTION 25 + These functions are used in conjunction with copying extended attributes from 26 + one file to another. Various types of copying (an "intent") check flags to 27 + determine which is allowed or not. 28 + .Pp 29 + The 30 + .Fn xattr_name_with_flags 31 + function returns an extended attribute name with the appropriate flags encoded 32 + as a string; the 33 + .Fn xattr_name_without_flags 34 + undoes this, giving the name of the extended attribute without the flags 35 + encoding. The slight inverse of that is 36 + .Fn xattr_flags_from_name , 37 + which will return the flags encoded in a name. 38 + .Pp 39 + The values returned by 40 + .Fn xattr_name_with_flags 41 + and 42 + .Fn xattr_name_without_flags 43 + are allocated using 44 + .Xr malloc 3 , 45 + and should be released by the caller, using 46 + .Xr free 3 . 47 + .Pp 48 + These functions also have an internal table of pre-defined names, maintained 49 + by the operating system. 50 + .Pp 51 + The function 52 + .Fn xattr_intent_with_flags 53 + will return 0 if the 54 + .Ar flags 55 + argument indicates it should not be preserved for the given 56 + intent, or 1 if it should. 57 + .Pp 58 + The function 59 + .Fn xattr_presere_for_intent 60 + combines the functions above, and will return zero if the 61 + named extended attribute should be preserved during a copy for 62 + the given intent. 63 + .Sh INTENT 64 + The type 65 + .Dt xattr_operation_intent_t 66 + is an integral type, which is used to indicate what the intent for the operation 67 + is. The following intent values are defined: 68 + .Bl -tag -width XATTR_OPERATION_INTENT_SHARE 69 + .It Dv XATTR_OPERATION_INTENT_COPY 70 + Indicates that the intent is to simply copy from the source to the destination. 71 + E.g., with cp. Most extended attributes should generally be preserved in this 72 + case. 73 + .It Dv XATTR_OPERATION_INTENT_SAVE 74 + Indicates that intent is to perform a save (perhaps as in a "safe save"). 75 + This differs from a copy in that the content may be changing; the destination 76 + may be over-writing or replacing the source, and som extended attributes should 77 + not be preserved during this process. 78 + .It Dv XATTR_OPERATION_INTENT_SHARE 79 + Indicates that the intent is to share, or export, the object. For example, 80 + saving as an attachment in an email message, or placing in a public folder. 81 + Sensitive information should probably not be preserved in this case. 82 + .It Dv XATTR_OPERATION_INTENT_SYNC 83 + Indicates that the intent is to sync the object to a service like iCloud. 84 + .El 85 + .Sh FLAGS 86 + Various flags are defined by the type 87 + .Dt xattr_flags_t ; 88 + the currently-defined values for this are 89 + .Bl -tag -width XATTR_FLAG_CONTENT_DEPENDENT 90 + .It Dv XATTR_FLAG_NO_EXPORT 91 + This indicates that the extended attribute should not be exported, or shared. 92 + This is used with 93 + .Dv XATTR_OPERATION_INTENT_SHARE . 94 + .It Dv XATTR_FLAG_CONTENT_DEPENDENT 95 + This indicates that the extended attribute is tied to the contents of the 96 + file (or vice versa), such that it should be re-created when the contents 97 + are changed. A checksum, for example, should not be copied, and would thus 98 + be marked with this flag. 99 + .It Dv XATTR_FLAG_NEVER_PRESERVE 100 + This indicates that the extended attribute should never be copied from a 101 + source object to a destination, no matter what the given intent is. 102 + .It Dv XATTR_FLAG_SYNCABLE 103 + This indicates that the extended attribute should be copied when the file 104 + is synced on services like iCloud. Sync services tends to want the metadata 105 + synced to be kept to a bare minimum, and may enforce additional restrictions 106 + on the acceptable size and number of extended attributes. 107 + .El 108 + .Sh EXAMPLE 109 + The following example is a simple function that, given an extended attribute 110 + name and an operation intent, will return whether or not the extended attribute 111 + should be copied. (This essentially does what 112 + .Fn xattr_preserve_for_intent 113 + does.) 114 + .Bd -literal -offset indent 115 + int 116 + ShouldCopyEA(const char *eaName, xattr_operation_intent_t intent) 117 + { 118 + xattr_flags_t flags = xattr_flags_from_name(eaName); 119 + return xattr_intent_with_flags(intent, flags); 120 + } 121 + .Ed 122 + .Sh HISTORY 123 + These functions first appeared in Mac OS in 2013.
+128
src/copyfile/xattr_properties.h
··· 1 + /* 2 + * Copyright (c) 2013 Apple, Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #ifndef _XATTR_PROPERTIES_H 25 + #define _XATTR_PROPERTIES_H 26 + 27 + #include <stdint.h> 28 + 29 + #include <sys/cdefs.h> 30 + #include <Availability.h> 31 + 32 + __BEGIN_DECLS 33 + 34 + /* 35 + * CopyOperationIntent_t is used to declare what the intent of the copy is. 36 + * Not a bit-field (for now, at least). 37 + * 38 + * CopyOperationIntentCopy indicates that the EA is attached to an object 39 + * that is simply being copied. E.g., cp src dst 40 + * 41 + * CopyOperationIntentSave indicates that the EA is attached to an object 42 + * being saved; as in a "safe save," the destination is being replaced by 43 + * the source, so the question is whether the EA should be applied to the 44 + * destination, or generated anew. 45 + * 46 + * CopyOperationIntentShare indicates that the EA is attached to an object that 47 + * is being given out to other people. For example, saving to a public folder, 48 + * or attaching to an email message. 49 + */ 50 + 51 + typedef enum { 52 + CopyOperationIntentCopy = 1, 53 + CopyOperationIntentSave, 54 + CopyOperationIntentShare, 55 + } CopyOperationIntent_t; 56 + 57 + typedef uint64_t CopyOperationProperties_t; 58 + 59 + /* 60 + * Various properties used to determine how to handle the xattr during 61 + * copying. The intent is that the default is reasonable for most xattrs. 62 + */ 63 + 64 + /* 65 + * kCopyOperationPropertyNoExport 66 + * Declare that the extended property should not be exported; this is 67 + * deliberately a bit vague, but this is used by CopyOperationIntentShare 68 + * to indicate not to preserve the xattr. 69 + */ 70 + #define kCopyOperationPropertyNoExport ((CopyOperationProperties_t)0x0001) 71 + 72 + /* 73 + * kCopyOperationPropertyContentDependent 74 + * Declares the extended attribute to be tied to the contents of the file (or 75 + * vice versa), such that it should be re-created when the contents of the 76 + * file change. Examples might include cryptographic keys, checksums, saved 77 + * position or search information, and text encoding. 78 + * 79 + * This property causes the EA to be preserved for copy and share, but not for 80 + * safe save. (In a safe save, the EA exists on the original, and will not 81 + * be copied to the new version.) 82 + */ 83 + #define kCopyOperationPropertyContentDependent ((CopyOperationProperties_t)0x0002) 84 + 85 + /* 86 + * kCopyOperationPropertyNeverPreserve 87 + * Declares that the extended attribute is never to be copied, for any 88 + * intention type. 89 + */ 90 + #define kCopyOperationPropertyNeverPreserve ((CopyOperationProperties_t)0x0004) 91 + 92 + #if 0 93 + /* 94 + * These are all going to be removed, and I don't believe anyone used them. 95 + */ 96 + /* 97 + * Given an extended attribute name, and a set of properties, return an 98 + * allocated C string with the name. This will return NULL on error; 99 + * errno may be set to ENOMEM if the new name cannot be allocated, or 100 + * ENAMETOOLONG if the new name is longer than the maximum for EAs (127 UTF8 101 + * characters). The caller must deallocate the return value otherwise. 102 + * 103 + * If no properties are set, it returns a copy of the EA name. 104 + * 105 + * If the EA name is in the internal list, and the properties are the same as 106 + * defined there, then it will also return an unmodified copy of the EA name. 107 + */ 108 + extern char *_xattrNameWithProperties(const char *, CopyOperationProperties_t) DEPRECATED_IN_MAC_OS_X_VERSION_10_10_AND_LATER; 109 + 110 + /* 111 + * Given an extended attribute name, which may or may not have properties encoded 112 + * as a suffix, return just the name of the attribute. E.g., com.example.mine#P 113 + * would return "com.example.mine". The return value will be NULL on error; 114 + * errno will be set to ENOMEM if it cannot be allocated. The caller must deallocate 115 + * the return value. 116 + */ 117 + extern char *_xattrNameWithoutProperties(const char *) DEPRECATED_IN_MAC_OS_X_VERSION_10_10_AND_LATER; 118 + 119 + /* 120 + * Given an EA name, return the properties. If the name is in the internal list, 121 + * those properties will be returned. Unknown property encodings are ignored. 122 + */ 123 + extern CopyOperationProperties_t _xattrPropertiesFromName(const char *) DEPRECATED_IN_MAC_OS_X_VERSION_10_10_AND_LATER; 124 + #endif /* 0 */ 125 + 126 + __END_DECLS 127 + 128 + #endif /* _XATTR_PROPERTIES_H */
+1 -1
src/libsystem/CMakeLists.txt
··· 39 39 add_library(system SHARED ${libsystem_sources}) 40 40 target_link_libraries(system system_malloc system_c system_kernel keymgr 41 41 system_m system_info system_notify unwind libdispatch_shared objc launch dyld 42 - removefile) 42 + removefile system_copyfile) 43 43 44 44 install(TARGETS system DESTINATION lib${SUFFIX}/darling) 45 45