xref: /haiku/src/kits/storage/SymLink.cpp (revision 9a17c3cfac5f2463b41b3f233975a2904ef10135)
1 //----------------------------------------------------------------------
2 //  This software is part of the OpenBeOS distribution and is covered
3 //  by the OpenBeOS license.
4 //---------------------------------------------------------------------
5 /*!
6 	\file SymLink.cpp
7 	BSymLink implementation.
8 */
9 
10 #include <new>
11 
12 #include <SymLink.h>
13 #include <Directory.h>
14 #include <Entry.h>
15 #include <Entry.h>
16 #include <Path.h>
17 #include "kernel_interface.h"
18 #include "storage_support.h"
19 
20 #ifdef USE_OPENBEOS_NAMESPACE
21 namespace OpenBeOS {
22 #endif
23 
24 // constructor
25 //! Creates an uninitialized BSymLink object.
26 BSymLink::BSymLink()
27 		: BNode()
28 	// WORKAROUND
29 		, fSecretEntry(new(nothrow) BEntry)
30 {
31 }
32 
33 // copy constructor
34 //! Creates a copy of the supplied BSymLink.
35 /*!	\param link the BSymLink object to be copied
36 */
37 BSymLink::BSymLink(const BSymLink &link)
38 		: BNode()
39 	// WORKAROUND
40 		, fSecretEntry(new(nothrow) BEntry)
41 {
42 	*this = link;
43 }
44 
45 // constructor
46 /*! \brief Creates a BSymLink and initializes it to the symbolic link referred
47 	to by the supplied entry_ref.
48 	\param ref the entry_ref referring to the symbolic link
49 */
50 BSymLink::BSymLink(const entry_ref *ref)
51 		: BNode()
52 	// WORKAROUND
53 		, fSecretEntry(new(nothrow) BEntry)
54 {
55 	SetTo(ref);
56 }
57 
58 // constructor
59 /*! \brief Creates a BSymLink and initializes it to the symbolic link referred
60 	to by the supplied BEntry.
61 	\param entry the BEntry referring to the symbolic link
62 */
63 BSymLink::BSymLink(const BEntry *entry)
64 		: BNode()
65 	// WORKAROUND
66 		, fSecretEntry(new(nothrow) BEntry)
67 {
68 	SetTo(entry);
69 }
70 
71 // constructor
72 /*! \brief Creates a BSymLink and initializes it to the symbolic link referred
73 	to by the supplied path name.
74 	\param path the symbolic link's path name
75 */
76 BSymLink::BSymLink(const char *path)
77 		: BNode()
78 	// WORKAROUND
79 		, fSecretEntry(new(nothrow) BEntry)
80 {
81 	SetTo(path);
82 }
83 
84 // constructor
85 /*! \brief Creates a BSymLink and initializes it to the symbolic link referred
86 	to by the supplied path name relative to the specified BDirectory.
87 	\param dir the BDirectory, relative to which the symbolic link's path name
88 		   is given
89 	\param path the symbolic link's path name relative to \a dir
90 */
91 BSymLink::BSymLink(const BDirectory *dir, const char *path)
92 		: BNode()
93 	// WORKAROUND
94 		, fSecretEntry(new(nothrow) BEntry)
95 {
96 	SetTo(dir, path);
97 }
98 
99 // destructor
100 //! Frees all allocated resources.
101 /*! If the BSymLink is properly initialized, the symbolic link's file
102 	descriptor is closed.
103 */
104 BSymLink::~BSymLink()
105 {
106 	// WORKAROUND
107 	delete fSecretEntry;
108 }
109 
110 // WORKAROUND
111 status_t
112 BSymLink::SetTo(const entry_ref *ref)
113 {
114 	status_t error = BNode::SetTo(ref);
115 	if (fSecretEntry) {
116 		fSecretEntry->Unset();
117 		if (error == B_OK)
118 			fSecretEntry->SetTo(ref);
119 	} else
120 		error = B_NO_MEMORY;
121 	return error;
122 }
123 
124 // WORKAROUND
125 status_t
126 BSymLink::SetTo(const BEntry *entry)
127 {
128 	status_t error = BNode::SetTo(entry);
129 	if (fSecretEntry) {
130 		fSecretEntry->Unset();
131 		if (error == B_OK)
132 			*fSecretEntry = *entry;
133 	} else
134 		error = B_NO_MEMORY;
135 	return error;
136 }
137 
138 // WORKAROUND
139 status_t
140 BSymLink::SetTo(const char *path)
141 {
142 	status_t error = BNode::SetTo(path);
143 	if (fSecretEntry) {
144 		fSecretEntry->Unset();
145 		if (error == B_OK)
146 			fSecretEntry->SetTo(path);
147 	} else
148 		error = B_NO_MEMORY;
149 	return error;
150 }
151 
152 // WORKAROUND
153 status_t
154 BSymLink::SetTo(const BDirectory *dir, const char *path)
155 {
156 	status_t error = BNode::SetTo(dir, path);
157 	if (fSecretEntry) {
158 		fSecretEntry->Unset();
159 		if (error == B_OK)
160 			fSecretEntry->SetTo(dir, path);
161 	} else
162 		error = B_NO_MEMORY;
163 	return error;
164 }
165 
166 // WORKAROUND
167 void
168 BSymLink::Unset()
169 {
170 	BNode::Unset();
171 	if (fSecretEntry)
172 		fSecretEntry->Unset();
173 }
174 
175 
176 // ReadLink
177 //! Reads the contents of the symbolic link into a buffer.
178 /*!	\param buf the buffer
179 	\param size the size of the buffer
180 	\return
181 	- the number of bytes written into the buffer
182 	- \c B_BAD_VALUE: \c NULL \a buf or the object doesn't refer to a symbolic
183 	  link.
184 	- \c B_FILE_ERROR: The object is not initialized.
185 	- some other error code
186 */
187 ssize_t
188 BSymLink::ReadLink(char *buf, size_t size)
189 {
190 /*
191 	status_t error = (buf ? B_OK : B_BAD_VALUE);
192 	if (error == B_OK && InitCheck() != B_OK)
193 		error = B_FILE_ERROR;
194 	if (error == B_OK)
195 		error = BPrivate::Storage::read_link(get_fd(), buf, size);
196 	return error;
197 */
198 // WORKAROUND
199 	status_t error = (buf ? B_OK : B_BAD_VALUE);
200 	if (error == B_OK && (InitCheck() != B_OK
201 		|| !fSecretEntry
202 		|| fSecretEntry->InitCheck() != B_OK)) {
203 		error = B_FILE_ERROR;
204 	}
205 	entry_ref ref;
206 	if (error == B_OK)
207 		error = fSecretEntry->GetRef(&ref);
208 	char path[B_PATH_NAME_LENGTH];
209 	if (error == B_OK)
210 		error = BPrivate::Storage::entry_ref_to_path(&ref, path, sizeof(path));
211 	if (error == B_OK)
212 		error = BPrivate::Storage::read_link(path, buf, size);
213 	return error;
214 }
215 
216 // MakeLinkedPath
217 /*!	\brief Combines a directory path and the contents of this symbolic link to
218 	an absolute path.
219 	\param dirPath the path name of the directory
220 	\param path the BPath object to be set to the resulting path name
221 	\return
222 	- \c the length of the resulting path name,
223 	- \c B_BAD_VALUE: \c NULL \a dirPath or \a path or the object doesn't
224 		 refer to a symbolic link.
225 	- \c B_FILE_ERROR: The object is not initialized.
226 	- \c B_NAME_TOO_LONG: The resulting path name is too long.
227 	- some other error code
228 */
229 ssize_t
230 BSymLink::MakeLinkedPath(const char *dirPath, BPath *path)
231 {
232 	// R5 seems to convert the dirPath to a BDirectory, which causes links to
233 	// be resolved, i.e. a "/tmp" dirPath expands to "/boot/var/tmp".
234 	// That does also mean, that the dirPath must exists!
235 	ssize_t result = (dirPath && path ? B_OK : B_BAD_VALUE);
236 	if (result == B_OK) {
237 		BDirectory dir(dirPath);
238 		result = dir.InitCheck();
239 		if (result == B_OK)
240 			result = MakeLinkedPath(&dir, path);
241 	}
242 	return result;
243 }
244 
245 // MakeLinkedPath
246 /*!	\brief Combines a directory path and the contents of this symbolic link to
247 	an absolute path.
248 	\param dir the BDirectory referring to the directory
249 	\param path the BPath object to be set to the resulting path name
250 	\return
251 	- \c the length of the resulting path name,
252 	- \c B_BAD_VALUE: \c NULL \a dir or \a path or the object doesn't
253 		 refer to a symbolic link.
254 	- \c B_FILE_ERROR: The object is not initialized.
255 	- \c B_NAME_TOO_LONG: The resulting path name is too long.
256 	- some other error code
257 */
258 ssize_t
259 BSymLink::MakeLinkedPath(const BDirectory *dir, BPath *path)
260 {
261 	ssize_t result = (dir && path ? 0 : B_BAD_VALUE);
262 	char contents[B_PATH_NAME_LENGTH];
263 	if (result == 0)
264 		result = ReadLink(contents, sizeof(contents));
265 	if (result >= 0) {
266 		if (BPrivate::Storage::is_absolute_path(contents))
267 			result = path->SetTo(contents);
268 		else
269 			result = path->SetTo(dir, contents);
270 		if (result == B_OK)
271 			result = strlen(path->Path());
272 	}
273 	return result;
274 }
275 
276 // IsAbsolute
277 //!	Returns whether this BSymLink refers to an absolute link.
278 /*!	/return
279 	- \c true, if the object is properly initialized and the symbolic link it
280 	  refers to is an absolute link,
281 	- \c false, otherwise.
282 */
283 bool
284 BSymLink::IsAbsolute()
285 {
286 	char contents[B_PATH_NAME_LENGTH];
287 	bool result = (ReadLink(contents, sizeof(contents)) >= 0);
288 	if (result)
289 		result = BPrivate::Storage::is_absolute_path(contents);
290 	return result;
291 }
292 
293 // WORKAROUND
294 BSymLink &
295 BSymLink::operator=(const BSymLink &link)
296 {
297 	if (&link != this) {	// no need to assign us to ourselves
298 		Unset();
299 		static_cast<BNode&>(*this) = link;
300 		if (fSecretEntry && link.fSecretEntry)
301 			*fSecretEntry = *link.fSecretEntry;
302 	}
303 	return *this;
304 }
305 
306 
307 void BSymLink::_ReservedSymLink1() {}
308 void BSymLink::_ReservedSymLink2() {}
309 void BSymLink::_ReservedSymLink3() {}
310 void BSymLink::_ReservedSymLink4() {}
311 void BSymLink::_ReservedSymLink5() {}
312 void BSymLink::_ReservedSymLink6() {}
313 
314 //! Returns the BSymLink's file descriptor.
315 /*! To be used instead of accessing the BNode's private \c fFd member directly.
316 	\return the file descriptor, or -1, if not properly initialized.
317 */
318 BPrivate::Storage::FileDescriptor
319 BSymLink::get_fd() const
320 {
321 	return fFd;
322 }
323 
324 
325 #ifdef USE_OPENBEOS_NAMESPACE
326 };		// namespace OpenBeOS
327 #endif
328 
329 
330 
331