mirror of
https://github.com/darlinghq/darling-xnu.git
synced 2024-11-23 04:29:53 +00:00
184 lines
5.5 KiB
C
184 lines
5.5 KiB
C
/*
|
|
* Copyright (c) 2015 Apple Inc. All rights reserved.
|
|
*
|
|
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
|
|
*
|
|
* This file contains Original Code and/or Modifications of Original Code
|
|
* as defined in and that are subject to the Apple Public Source License
|
|
* Version 2.0 (the 'License'). You may not use this file except in
|
|
* compliance with the License. The rights granted to you under the License
|
|
* may not be used to create, or enable the creation or redistribution of,
|
|
* unlawful or unlicensed copies of an Apple operating system, or to
|
|
* circumvent, violate, or enable the circumvention or violation of, any
|
|
* terms of an Apple operating system software license agreement.
|
|
*
|
|
* Please obtain a copy of the License at
|
|
* http://www.opensource.apple.com/apsl/ and read it before using this file.
|
|
*
|
|
* The Original Code and all software distributed under the License are
|
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
|
* Please see the License for the specific language governing rights and
|
|
* limitations under the License.
|
|
*
|
|
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
|
|
*/
|
|
|
|
// -- Document ID Tombstone Support --
|
|
|
|
#include <stdint.h>
|
|
#include <sys/resource.h>
|
|
#include <sys/signal.h>
|
|
#include <sys/vfs_context.h>
|
|
#include <sys/doc_tombstone.h>
|
|
#include <sys/vnode_internal.h>
|
|
#include <sys/fsevents.h>
|
|
#include <kern/thread.h>
|
|
#include <kern/kalloc.h>
|
|
#include <string.h>
|
|
|
|
//
|
|
// This function gets the doc_tombstone structure for the
|
|
// current thread. If the thread doesn't have one, the
|
|
// structure is allocated.
|
|
//
|
|
struct doc_tombstone *
|
|
doc_tombstone_get(void)
|
|
{
|
|
struct uthread *ut;
|
|
ut = get_bsdthread_info(current_thread());
|
|
|
|
if (ut->t_tombstone == NULL) {
|
|
ut->t_tombstone = kalloc_flags(sizeof(struct doc_tombstone),
|
|
Z_WAITOK | Z_ZERO);
|
|
}
|
|
|
|
return ut->t_tombstone;
|
|
}
|
|
|
|
//
|
|
// This routine clears out the current tombstone for the
|
|
// current thread and if necessary passes the doc-id of
|
|
// the tombstone on to the dst_cnode.
|
|
//
|
|
// The caller is responsible for generating the appropriate
|
|
// fsevents.
|
|
//
|
|
void
|
|
doc_tombstone_clear(struct doc_tombstone *ut, vnode_t *old_vpp)
|
|
{
|
|
uint64_t old_id = ut->t_lastop_document_id;
|
|
|
|
ut->t_lastop_document_id = 0;
|
|
ut->t_lastop_parent = NULL;
|
|
ut->t_lastop_parent_vid = 0;
|
|
ut->t_lastop_filename[0] = '\0';
|
|
|
|
//
|
|
// If the lastop item is still the same and needs to be cleared,
|
|
// clear it. The following isn't ideal because the vnode might
|
|
// have been recycled.
|
|
//
|
|
if (old_vpp) {
|
|
*old_vpp = NULL;
|
|
if (old_id && ut->t_lastop_item
|
|
&& vnode_vid(ut->t_lastop_item) == ut->t_lastop_item_vid) {
|
|
int res = vnode_get(ut->t_lastop_item);
|
|
if (!res) {
|
|
// Need to check vid again
|
|
if (vnode_vid(ut->t_lastop_item) == ut->t_lastop_item_vid
|
|
&& !ISSET(ut->t_lastop_item->v_lflag, VL_TERMINATE)) {
|
|
*old_vpp = ut->t_lastop_item;
|
|
} else {
|
|
vnode_put(ut->t_lastop_item);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// last, clear these now that we're all done
|
|
ut->t_lastop_item = NULL;
|
|
ut->t_lastop_fileid = 0;
|
|
ut->t_lastop_item_vid = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// This function is used to filter out operations on temp
|
|
// filenames. We have to filter out operations on certain
|
|
// temp filenames to work-around questionable application
|
|
// behavior from apps like Autocad that perform unusual
|
|
// sequences of file system operations for a "safe save".
|
|
bool
|
|
doc_tombstone_should_ignore_name(const char *nameptr, int len)
|
|
{
|
|
size_t real_len;
|
|
if (len == 0) {
|
|
real_len = strlen(nameptr);
|
|
} else {
|
|
real_len = (size_t)len;
|
|
}
|
|
|
|
if (strncmp(nameptr, "atmp", 4) == 0
|
|
|| (real_len > 4 && strncmp(nameptr + real_len - 4, ".bak", 4) == 0)
|
|
|| (real_len > 4 && strncmp(nameptr + real_len - 4, ".tmp", 4) == 0)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Decide if we need to save a tombstone or not. Normally we always
|
|
// save a tombstone - but if there already is one and the name we're
|
|
// given is an ignorable name, then we will not save a tombstone.
|
|
//
|
|
bool
|
|
doc_tombstone_should_save(struct doc_tombstone *ut, struct vnode *vp,
|
|
struct componentname *cnp)
|
|
{
|
|
if (cnp->cn_nameptr == NULL) {
|
|
return false;
|
|
}
|
|
|
|
if (ut->t_lastop_document_id && ut->t_lastop_item == vp
|
|
&& doc_tombstone_should_ignore_name(cnp->cn_nameptr, cnp->cn_namelen)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// This function saves a tombstone for the given vnode and name. The
|
|
// tombstone represents the parent directory and name where the document
|
|
// used to live and the document-id of that file. This info is recorded
|
|
// in the doc_tombstone structure hanging off the uthread (which assumes
|
|
// that all safe-save operations happen on the same thread).
|
|
//
|
|
// If later on the same parent/name combo comes back into existence then
|
|
// we'll preserve the doc-id from this vnode onto the new vnode.
|
|
//
|
|
// The caller is responsible for generating the appropriate
|
|
// fsevents.
|
|
//
|
|
void
|
|
doc_tombstone_save(struct vnode *dvp, struct vnode *vp,
|
|
struct componentname *cnp, uint64_t doc_id,
|
|
ino64_t file_id)
|
|
{
|
|
struct doc_tombstone *ut;
|
|
ut = doc_tombstone_get();
|
|
|
|
ut->t_lastop_parent = dvp;
|
|
ut->t_lastop_parent_vid = vnode_vid(dvp);
|
|
ut->t_lastop_fileid = file_id;
|
|
ut->t_lastop_item = vp;
|
|
ut->t_lastop_item_vid = vp ? vnode_vid(vp) : 0;
|
|
ut->t_lastop_document_id = doc_id;
|
|
|
|
strlcpy((char *)&ut->t_lastop_filename[0], cnp->cn_nameptr, sizeof(ut->t_lastop_filename));
|
|
}
|