]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/doc_tombstone.c
xnu-4570.31.3.tar.gz
[apple/xnu.git] / bsd / vfs / doc_tombstone.c
1 /*
2 * Copyright (c) 2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 // -- Document ID Tombstone Support --
30
31 #include <stdint.h>
32 #include <sys/resource.h>
33 #include <sys/signal.h>
34 #include <sys/vfs_context.h>
35 #include <sys/doc_tombstone.h>
36 #include <sys/vnode_internal.h>
37 #include <sys/fsevents.h>
38 #include <kern/thread.h>
39 #include <kern/kalloc.h>
40 #include <string.h>
41
42 //
43 // This function gets the doc_tombstone structure for the
44 // current thread. If the thread doesn't have one, the
45 // structure is allocated.
46 //
47 struct doc_tombstone *
48 doc_tombstone_get(void)
49 {
50 struct uthread *ut;
51 ut = get_bsdthread_info(current_thread());
52
53 if (ut->t_tombstone == NULL) {
54 ut->t_tombstone = kalloc(sizeof(struct doc_tombstone));
55 if (ut->t_tombstone) {
56 memset(ut->t_tombstone, 0, sizeof(struct doc_tombstone));
57 }
58 }
59
60 return ut->t_tombstone;
61 }
62
63 //
64 // This routine clears out the current tombstone for the
65 // current thread and if necessary passes the doc-id of
66 // the tombstone on to the dst_cnode.
67 //
68 // The caller is responsible for generating the appropriate
69 // fsevents.
70 //
71 void
72 doc_tombstone_clear(struct doc_tombstone *ut, vnode_t *old_vpp)
73 {
74 uint32_t old_id = ut->t_lastop_document_id;
75
76 ut->t_lastop_document_id = 0;
77 ut->t_lastop_parent = NULL;
78 ut->t_lastop_parent_vid = 0;
79 ut->t_lastop_filename[0] = '\0';
80
81 //
82 // If the lastop item is still the same and needs to be cleared,
83 // clear it. The following isn't ideal because the vnode might
84 // have been recycled.
85 //
86 if (old_vpp) {
87 *old_vpp = NULL;
88 if (old_id && ut->t_lastop_item
89 && vnode_vid(ut->t_lastop_item) == ut->t_lastop_item_vid) {
90 int res = vnode_get(ut->t_lastop_item);
91 if (!res) {
92 // Need to check vid again
93 if (vnode_vid(ut->t_lastop_item) == ut->t_lastop_item_vid
94 && !ISSET(ut->t_lastop_item->v_lflag, VL_TERMINATE))
95 *old_vpp = ut->t_lastop_item;
96 else
97 vnode_put(ut->t_lastop_item);
98 }
99 }
100 }
101
102 // last, clear these now that we're all done
103 ut->t_lastop_item = NULL;
104 ut->t_lastop_fileid = 0;
105 ut->t_lastop_item_vid = 0;
106 }
107
108
109 //
110 // This function is used to filter out operations on temp
111 // filenames. We have to filter out operations on certain
112 // temp filenames to work-around questionable application
113 // behavior from apps like Autocad that perform unusual
114 // sequences of file system operations for a "safe save".
115 bool doc_tombstone_should_ignore_name(const char *nameptr, int len)
116 {
117 if (len == 0) {
118 len = strlen(nameptr);
119 }
120
121 if ( strncmp(nameptr, "atmp", 4) == 0
122 || (len > 4 && strncmp(nameptr+len-4, ".bak", 4) == 0)
123 || (len > 4 && strncmp(nameptr+len-4, ".tmp", 4) == 0)) {
124 return true;
125 }
126
127 return false;
128 }
129
130 //
131 // Decide if we need to save a tombstone or not. Normally we always
132 // save a tombstone - but if there already is one and the name we're
133 // given is an ignorable name, then we will not save a tombstone.
134 //
135 bool doc_tombstone_should_save(struct doc_tombstone *ut, struct vnode *vp,
136 struct componentname *cnp)
137 {
138 if (cnp->cn_nameptr == NULL) {
139 return false;
140 }
141
142 if (ut->t_lastop_document_id && ut->t_lastop_item == vp
143 && doc_tombstone_should_ignore_name(cnp->cn_nameptr, cnp->cn_namelen)) {
144 return false;
145 }
146
147 return true;
148 }
149
150 //
151 // This function saves a tombstone for the given vnode and name. The
152 // tombstone represents the parent directory and name where the document
153 // used to live and the document-id of that file. This info is recorded
154 // in the doc_tombstone structure hanging off the uthread (which assumes
155 // that all safe-save operations happen on the same thread).
156 //
157 // If later on the same parent/name combo comes back into existence then
158 // we'll preserve the doc-id from this vnode onto the new vnode.
159 //
160 // The caller is responsible for generating the appropriate
161 // fsevents.
162 //
163 void
164 doc_tombstone_save(struct vnode *dvp, struct vnode *vp,
165 struct componentname *cnp, uint64_t doc_id,
166 ino64_t file_id)
167 {
168 struct doc_tombstone *ut;
169 ut = doc_tombstone_get();
170
171 ut->t_lastop_parent = dvp;
172 ut->t_lastop_parent_vid = vnode_vid(dvp);
173 ut->t_lastop_fileid = file_id;
174 ut->t_lastop_item = vp;
175 ut->t_lastop_item_vid = vp ? vnode_vid(vp) : 0;
176 ut->t_lastop_document_id = doc_id;
177
178 strlcpy((char *)&ut->t_lastop_filename[0], cnp->cn_nameptr, sizeof(ut->t_lastop_filename));
179 }