1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * BSD 3 Clause License
8  *
9  * Copyright (c) 2007, The Storage Networking Industry Association.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 	- Redistributions of source code must retain the above copyright
15  *	  notice, this list of conditions and the following disclaimer.
16  *
17  * 	- Redistributions in binary form must reproduce the above copyright
18  *	  notice, this list of conditions and the following disclaimer in
19  *	  the documentation and/or other materials provided with the
20  *	  distribution.
21  *
22  *	- Neither the name of The Storage Networking Industry Association (SNIA)
23  *	  nor the names of its contributors may be used to endorse or promote
24  *	  products derived from this software without specific prior written
25  *	  permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <sys/queue.h>
43 #include <sys/syslog.h>
44 #include "tlm.h"
45 #include "tlm_proto.h"
46 
47 #define	HL_DBG_INIT		0x0001
48 #define	HL_DBG_CLEANUP	0x0002
49 #define	HL_DBG_GET	0x0004
50 #define	HL_DBG_ADD	0x0008
51 
52 static int hardlink_q_dbg = -1;
53 
54 
55 struct hardlink_q *
56 hardlink_q_init()
57 {
58 	struct hardlink_q *qhead;
59 
60 	qhead = (struct hardlink_q *)malloc(sizeof (struct hardlink_q));
61 	if (qhead) {
62 		/* LINTED: E_CONSTANT_CONDITION */
63 		SLIST_INIT(qhead);
64 	}
65 
66 	if (hardlink_q_dbg & HL_DBG_INIT)
67 		NDMP_LOG(LOG_DEBUG, "qhead = %p", qhead);
68 
69 	return (qhead);
70 }
71 
72 void
73 hardlink_q_cleanup(struct hardlink_q *hl_q)
74 {
75 	struct hardlink_node *hl;
76 
77 	if (hardlink_q_dbg & HL_DBG_CLEANUP)
78 		NDMP_LOG(LOG_DEBUG, "(1): qhead = %p", hl_q);
79 
80 	if (!hl_q)
81 		return;
82 
83 	while (!SLIST_EMPTY(hl_q)) {
84 		hl = SLIST_FIRST(hl_q);
85 
86 		if (hardlink_q_dbg & HL_DBG_CLEANUP)
87 			NDMP_LOG(LOG_DEBUG, "(2): remove node, inode = %lu",
88 			    hl->inode);
89 
90 		/* LINTED: E_CONSTANT_CONDITION */
91 		SLIST_REMOVE_HEAD(hl_q, next_hardlink);
92 
93 		/* remove the temporary file */
94 		if (hl->is_tmp) {
95 			if (hl->path) {
96 				NDMP_LOG(LOG_DEBUG, "(3): remove temp file %s",
97 				    hl->path);
98 				if (remove(hl->path)) {
99 					NDMP_LOG(LOG_DEBUG,
100 					    "error removing temp file");
101 				}
102 			} else {
103 				NDMP_LOG(LOG_DEBUG, "no link name, inode = %lu",
104 				    hl->inode);
105 			}
106 		}
107 
108 		if (hl->path)
109 			free(hl->path);
110 		free(hl);
111 	}
112 
113 	free(hl_q);
114 }
115 
116 /*
117  * Return 0 if a list node has the same inode, and initialize offset and path
118  * with the information in the list node.
119  * Return -1 if no matching node is found.
120  */
121 int
122 hardlink_q_get(struct hardlink_q *hl_q, unsigned long inode,
123     unsigned long long *offset, char **path)
124 {
125 	struct hardlink_node *hl;
126 
127 	if (hardlink_q_dbg & HL_DBG_GET)
128 		NDMP_LOG(LOG_DEBUG, "(1): qhead = %p, inode = %lu",
129 		    hl_q, inode);
130 
131 	if (!hl_q)
132 		return (-1);
133 
134 	SLIST_FOREACH(hl, hl_q, next_hardlink) {
135 		if (hardlink_q_dbg & HL_DBG_GET)
136 			NDMP_LOG(LOG_DEBUG, "(2): checking, inode = %lu",
137 			    hl->inode);
138 
139 		if (hl->inode != inode)
140 			continue;
141 
142 		if (offset)
143 			*offset = hl->offset;
144 
145 		if (path)
146 			*path = hl->path;
147 
148 		return (0);
149 	}
150 
151 	return (-1);
152 }
153 
154 /*
155  * Add a node to hardlink_q.  Reject a duplicated entry.
156  *
157  * Return 0 if successful, and -1 if failed.
158  */
159 int
160 hardlink_q_add(struct hardlink_q *hl_q, unsigned long inode,
161     unsigned long long offset, char *path, int is_tmp_file)
162 {
163 	struct hardlink_node *hl;
164 
165 	if (hardlink_q_dbg & HL_DBG_ADD)
166 		NDMP_LOG(LOG_DEBUG,
167 		    "(1): qhead = %p, inode = %lu, path = %p (%s)",
168 		    hl_q, inode, path, path? path : "(--)");
169 
170 	if (!hl_q)
171 		return (-1);
172 
173 	if (!hardlink_q_get(hl_q, inode, 0, 0)) {
174 		NDMP_LOG(LOG_DEBUG, "hardlink (inode = %lu) exists in queue %p",
175 		    inode, hl_q);
176 		return (-1);
177 	}
178 
179 	hl = (struct hardlink_node *)malloc(sizeof (struct hardlink_node));
180 	if (!hl)
181 		return (-1);
182 
183 	hl->inode = inode;
184 	hl->offset = offset;
185 	hl->is_tmp = is_tmp_file;
186 	if (path)
187 		hl->path = strdup(path);
188 	else
189 		hl->path = NULL;
190 
191 	if (hardlink_q_dbg & HL_DBG_ADD)
192 		NDMP_LOG(LOG_DEBUG,
193 		    "(2): added node, inode = %lu, path = %p (%s)",
194 		    hl->inode, hl->path, hl->path? hl->path : "(--)");
195 
196 	/* LINTED: E_CONSTANT_CONDITION */
197 	SLIST_INSERT_HEAD(hl_q, hl, next_hardlink);
198 
199 	return (0);
200 }
201 
202 int
203 hardlink_q_dump(struct hardlink_q *hl_q)
204 {
205 	struct hardlink_node *hl;
206 
207 	if (!hl_q)
208 		return (0);
209 
210 	(void) printf("Dumping hardlink_q, head = %p:\n", (void *) hl_q);
211 
212 	SLIST_FOREACH(hl, hl_q, next_hardlink)
213 		(void) printf(
214 		    "\t node = %lu, offset = %llu, path = %s, is_tmp = %d\n",
215 		    hl->inode, hl->offset, hl->path? hl->path : "--",
216 		    hl->is_tmp);
217 
218 	return (0);
219 }
220