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