1/*
2 * Copyright (c) 2004 Apple Computer, 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 _WEBDAV_CACHE_H_INCLUDE
25#define _WEBDAV_CACHE_H_INCLUDE
26
27#include <sys/types.h>
28#include <sys/queue.h>
29#include <CoreServices/CoreServices.h>
30
31/*****************************************************************************/
32
33/* define node_head structure */
34LIST_HEAD(node_head, node_entry);
35
36struct webdav_stat_attr {
37	struct stat				attr_stat;			/* stat attributes */
38	struct	timespec		attr_create_time;	/* time file was created */
39	void* data;
40	Boolean start;
41};
42
43struct node_entry
44{
45	LIST_ENTRY(node_entry)  entries;				/* the other nodes on the parent's children list */
46	struct node_entry		*parent;				/* the parent node_entry, or NULL if this is the root node */
47	LIST_HEAD(, node_entry) children;				/* this node's children (if any) */
48
49	/*
50	 * Node identification fields
51	 */
52	size_t					name_length;			/* length of name */
53	char					*name;					/* the utf8 name */
54	CFStringRef				name_ref;				/* the name as a CFString */
55	webdav_ino_t			fileid;					/* file ID number */
56	webdav_filetype_t		node_type;				/* (int) either WEBDAV_FILE_TYPE or WEBDAV_DIR_TYPE */
57	u_int32_t				flags;
58	opaque_id				nodeid;					/* opaque_id assigned to this node */
59	time_t					node_time;				/* local time - when node was validated on server */
60
61	/*
62	 * Attribute fields
63	 *
64	 * Set attr_time to 0 and free the memory used by attr_ref (if any) to invalidate attributes.
65	 */
66	uid_t					attr_uid;				/* user authorized to use attribute data */
67	time_t					attr_time;				/* local time - when attribute data was received from server */
68	struct webdav_stat_attr	attr_stat_info;			/* stat attributes + misc. timestamps */
69
70	/* file system specific attribute data */
71	time_t					attr_appledoubleheader_time; /* local time - when attr_appledoubleheader was received from server */
72	char					*attr_appledoubleheader; /* NULL if no appledoubleheader data */
73
74	/*
75	 * File cache fields
76	 *
77	 * Clear the nodeInFileList flag bit and insert into the from the file_list make it a valid cache file.
78	 *
79	 * Clear the nodeInFileList flag bit and remove from the file_list to invalidate a cache file. Don't forget to free the
80	 * file_ref before you free the node.
81	 *
82	 * A valid cache file can be either active (the file or directory it is a
83	 * cache for is open) or inactive (the file or directory it is a cache for
84	 * is closed). Active cache files have a file_inactive_time of zero;
85	 * inactive cache files have the time the cache file was made inactive so
86	 * that they can be aged out of the cache.
87	 */
88	LIST_ENTRY(node_entry)  file_list;				/* the g_file_list */
89	int						file_fd;				/* the cache file's file descriptor or -1 if none */
90	u_int32_t				file_status;			/* the status of the cache file download:
91													 *		WEBDAV_DOWNLOAD_NEVER (never downloaded)
92													 *		WEBDAV_DOWNLOAD_IN_PROGRESS (download still in progress)
93													 *		WEBDAV_DOWNLOAD_FINISHED (download complete)
94													 *		WEBDAV_DOWNLOAD_ABORTED (download was stopped before complete because of close or error)
95													 * If WEBDAV_DOWNLOAD_TERMINATED is set, an in-progress download should be stopped.
96													 * Note: the download_status field should be word aligned.
97													 */
98	time_t					file_validated_time;	/* local time - when cache file was last validated by server */
99	time_t					file_inactive_time;		/* local time - when cache file was made inactive (the file this cache is for was closed) - 0 if active */
100	/* file system specific file cache data */
101	time_t					file_last_modified;		/* the HTTP-date converted to time_t from the Last-Modified entity-header or from the getlastmodified property, or -1 if no valid Last-Modified date */
102	char					*file_entity_tag;		/* The entity-tag from the ETag response-header or from the getetag property */
103	uid_t					file_locktoken_uid;		/* the uid associated with the locktoken (filesystem_close and filesystem_lock need it to renew locks and to unlock). */
104	char					*file_locktoken;		/* the lock token, or NULL */
105
106	/* Context for sequential writes */
107	struct stream_put_ctx* put_ctx;
108
109	/* Fields used for HTTP 3xx Redirects */
110	boolean_t				isRedirected;		/* TRUE if this node has been redirected */
111	size_t					redir_name_length;	/* length of redirected name */
112	char					*redir_name;		/* the redirected utf8 name (From Location header of 3xx response) */
113};
114
115#define WEBDAV_DOWNLOAD_NEVER		0
116#define WEBDAV_DOWNLOAD_IN_PROGRESS	1
117#define WEBDAV_DOWNLOAD_FINISHED	2
118#define WEBDAV_DOWNLOAD_ABORTED		3
119#define WEBDAV_DOWNLOAD_STATUS_MASK	0x7fffffff
120#define WEBDAV_DOWNLOAD_TERMINATED	0x80000000
121
122/* node_entry flags */
123enum
124{
125	nodeDeletedBit			= 0,			/* the node is deleted and is on the deleted list */
126	nodeDeletedMask			= 0x00000001,
127	nodeInFileListBit		= 1,			/* the node is cached and is on the file list */
128	nodeInFileListMask		= 0x00000002,
129	nodeRecentBit			= 2,			/* the file node was recently created by this client or the directory was recently read */
130	nodeRecentMask			= 0x00000004
131};
132
133/*****************************************************************************/
134
135#define ATTRIBUTES_TIMEOUT_MIN		2		/* Minimum number of seconds attributes are valid */
136#define ATTRIBUTES_TIMEOUT_MAX		60		/* Maximum number of seconds attributes are valid */
137#define FILE_VALIDATION_TIMEOUT		60		/* Number of seconds file is valid from file_validated_time */
138#define FILE_CACHE_TIMEOUT			3600	/* 1 hour */
139#define FILE_RECENTLY_CREATED_TIMEOUT	1	/* Maximum number of seconds to skip GETs on opens after a create */
140
141#define NODE_IS_DELETED(node)		(((node)->flags & nodeDeletedMask) != 0)
142
143int node_appledoubleheader_valid(
144	struct node_entry *node,
145	uid_t uid);
146int node_attributes_valid(
147	struct node_entry *node,
148	uid_t uid);
149
150#define NODE_FILE_IS_CACHED(node)	( ((node)->flags & nodeInFileListMask) != 0 )
151#define NODE_FILE_IS_OPEN(node)		( (node)->file_inactive_time == 0 )
152#define NODE_FILE_CACHE_INVALID(node) ( ((node)->file_inactive_time != 0) && \
153									  (time(NULL) >= ((node)->file_inactive_time + FILE_CACHE_TIMEOUT)) )
154#define NODE_FILE_INVALID(node)		( ((node)->file_validated_time == 0) || \
155									  (time(NULL) >= ((node)->file_validated_time + FILE_VALIDATION_TIMEOUT)) )
156#define NODE_FILE_RECENTLY_CREATED(node) ( ((node)->node_time != 0) && \
157									  (((node)->flags & nodeRecentMask) != 0) && \
158									  (time(NULL) <= ((node)->node_time + FILE_RECENTLY_CREATED_TIMEOUT)) )
159
160/*****************************************************************************/
161
162int nodecache_init(
163	size_t name_length,				/* length of root node name */
164	char *name,						/* the utf8 name of root node */
165	struct node_entry **root_node);	/* the root node */
166
167int nodecache_get_node(
168	struct node_entry *parent,		/* the parent node_entry */
169	size_t name_length,				/* length of name */
170	const char *name,				/* the utf8 name of the node */
171	int make_entry,					/* TRUE if a new node_entry should be created if needed*/
172	int client_created,				/* TRUE if this client created the node (used in conjunction with make_entry */
173	webdav_filetype_t node_type,	/* if make_entry is TRUE, the type of node to create */
174	struct node_entry **node);		/* the found (or new) node_entry */
175
176void nodecache_free_nodes(void);
177
178int nodecache_move_node(
179	struct node_entry *node,		/* the node_entry to move */
180	struct node_entry *new_parent,  /* the new parent node_entry */
181	size_t new_name_length,			/* length of new_name or 0 if not renaming */
182	char *new_name);				/* the utf8 new name of the node or NULL */
183
184int nodecache_delete_node(
185	struct node_entry *node,		/* the node_entry to delete */
186	int recursive);					/* delete recursively if node is a directory */
187
188int nodecache_add_attributes(
189	struct node_entry *node,		/* the node_entry to update or add attributes_entry to */
190	uid_t uid,						/* the uid these attributes are valid for */
191	struct webdav_stat_attr *statp,	/* the stat buffer */
192	char *appledoubleheader);		/* pointer appledoubleheader or NULL */
193
194int nodecache_remove_attributes(
195	struct node_entry *node);		/* the node_entry to remove attributes from */
196
197void nodecache_invalidate_caches(void);
198
199int nodecache_add_file_cache(
200	struct node_entry *node,		/* the node_entry to add a file_cache_entry to */
201	int fd);						/* the file descriptor of the cache file */
202
203void nodecache_remove_file_cache(
204	struct node_entry *node);		/* the node_entry to remove file_cache_entry from */
205
206struct node_entry *nodecache_get_next_file_cache_node(
207	int get_first);					/* if true, return first file cache node; otherwise, the next one */
208
209int nodecache_get_path_from_node(
210	struct node_entry *node,		/* -> node */
211	bool *pathHasRedirection,		/* true if path contains a URL from a redirected node (http 3xx redirect) */
212	char **path);					/* <- relative path to root node */
213
214int nodecache_redirect_node(
215	CFURLRef url,						/* original url that caused the redirect */
216	struct node_entry *redirected_node,	/* the node being redirected NULL if root node */
217	CFHTTPMessageRef responseRef,		/* the 3xx redirect response message */
218	CFIndex statusCode);				/* Actual 3xx status code from response message */
219
220int nodecache_invalidate_directory_node_time(
221	struct node_entry *dir_node);	/* parent directory node */
222
223int nodecache_delete_invalid_directory_nodes(
224	struct node_entry *dir_node);	/* parent directory node */
225
226CFURLRef nodecache_get_baseURL(void);
227
228CFArrayRef nodecache_get_locktokens(
229	struct node_entry *a_node);		/* node or directory node */
230
231void lock_node_cache(void);
232void unlock_node_cache(void);
233
234
235/*****************************************************************************/
236
237#if 0
238void nodecache_display_node_tree(void);
239void nodecache_display_file_cache(void);
240#endif
241
242/*****************************************************************************/
243
244#endif
245