1/*
2 * Copyright 2002-2009, Haiku Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Tyler Dauwalder
7 *		Ingo Weinhold, ingo_weinhold@gmx.de
8 */
9
10
11/*!	\file SymLink.cpp
12	BSymLink implementation.
13*/
14
15
16#include <new>
17#include <string.h>
18
19#include <SymLink.h>
20#include <Directory.h>
21#include <Entry.h>
22#include <Path.h>
23
24#include <syscalls.h>
25
26#include "storage_support.h"
27
28using namespace std;
29
30
31//! Creates an uninitialized BSymLink object.
32BSymLink::BSymLink()
33{
34}
35
36
37//! Creates a copy of the supplied BSymLink.
38/*!	\param link the BSymLink object to be copied
39*/
40BSymLink::BSymLink(const BSymLink &link)
41	:
42	BNode(link)
43{
44}
45
46
47/*! \brief Creates a BSymLink and initializes it to the symbolic link referred
48	to by the supplied entry_ref.
49	\param ref the entry_ref referring to the symbolic link
50*/
51BSymLink::BSymLink(const entry_ref *ref)
52	:
53	BNode(ref)
54{
55}
56
57
58/*! \brief Creates a BSymLink and initializes it to the symbolic link referred
59	to by the supplied BEntry.
60	\param entry the BEntry referring to the symbolic link
61*/
62BSymLink::BSymLink(const BEntry *entry)
63		: BNode(entry)
64{
65}
66
67
68/*! \brief Creates a BSymLink and initializes it to the symbolic link referred
69	to by the supplied path name.
70	\param path the symbolic link's path name
71*/
72BSymLink::BSymLink(const char *path)
73	:
74	BNode(path)
75{
76}
77
78
79/*! \brief Creates a BSymLink and initializes it to the symbolic link referred
80	to by the supplied path name relative to the specified BDirectory.
81	\param dir the BDirectory, relative to which the symbolic link's path name
82		   is given
83	\param path the symbolic link's path name relative to \a dir
84*/
85BSymLink::BSymLink(const BDirectory *dir, const char *path)
86	:
87	BNode(dir, path)
88{
89}
90
91
92//! Frees all allocated resources.
93/*! If the BSymLink is properly initialized, the symbolic link's file
94	descriptor is closed.
95*/
96BSymLink::~BSymLink()
97{
98}
99
100
101//! Reads the contents of the symbolic link into a buffer.
102/*!	The string written to the buffer will be null-terminated.
103	\param buf the buffer
104	\param size the size of the buffer
105	\return
106	- the number of bytes written into the buffer
107	- \c B_BAD_VALUE: \c NULL \a buf or the object doesn't refer to a symbolic
108	  link.
109	- \c B_FILE_ERROR: The object is not initialized.
110	- some other error code
111*/
112ssize_t
113BSymLink::ReadLink(char *buffer, size_t size)
114{
115	if (!buffer)
116		return B_BAD_VALUE;
117	if (InitCheck() != B_OK)
118		return B_FILE_ERROR;
119
120	size_t linkLen = size;
121	status_t error = _kern_read_link(get_fd(), NULL, buffer, &linkLen);
122	if (error < B_OK)
123		return error;
124
125	// null-terminate
126	if (linkLen >= size)
127		return B_BUFFER_OVERFLOW;
128	buffer[linkLen] = '\0';
129
130	return linkLen;
131}
132
133
134/*!	\brief Combines a directory path and the contents of this symbolic link to
135	an absolute path.
136	\param dirPath the path name of the directory
137	\param path the BPath object to be set to the resulting path name
138	\return
139	- \c the length of the resulting path name,
140	- \c B_BAD_VALUE: \c NULL \a dirPath or \a path or the object doesn't
141		 refer to a symbolic link.
142	- \c B_FILE_ERROR: The object is not initialized.
143	- \c B_NAME_TOO_LONG: The resulting path name is too long.
144	- some other error code
145*/
146ssize_t
147BSymLink::MakeLinkedPath(const char *dirPath, BPath *path)
148{
149	// BeOS seems to convert the dirPath to a BDirectory, which causes links to
150	// be resolved.
151	// This does also mean that the dirPath must exist!
152	if (!dirPath || !path)
153		return B_BAD_VALUE;
154	BDirectory dir(dirPath);
155	ssize_t result = dir.InitCheck();
156	if (result == B_OK)
157		result = MakeLinkedPath(&dir, path);
158	return result;
159}
160
161
162/*!	\brief Combines a directory path and the contents of this symbolic link to
163	an absolute path.
164	\param dir the BDirectory referring to the directory
165	\param path the BPath object to be set to the resulting path name
166	\return
167	- \c the length of the resulting path name,
168	- \c B_BAD_VALUE: \c NULL \a dir or \a path or the object doesn't
169		 refer to a symbolic link.
170	- \c B_FILE_ERROR: The object is not initialized.
171	- \c B_NAME_TOO_LONG: The resulting path name is too long.
172	- some other error code
173*/
174ssize_t
175BSymLink::MakeLinkedPath(const BDirectory *dir, BPath *path)
176{
177	if (!dir || !path)
178		return B_BAD_VALUE;
179	char contents[B_PATH_NAME_LENGTH];
180	ssize_t result = ReadLink(contents, sizeof(contents));
181	if (result >= 0) {
182		if (BPrivate::Storage::is_absolute_path(contents))
183			result = path->SetTo(contents);
184		else
185			result = path->SetTo(dir, contents);
186		if (result == B_OK)
187			result = strlen(path->Path());
188	}
189	return result;
190}
191
192
193//!	Returns whether this BSymLink refers to an absolute link.
194/*!	/return
195	- \c true, if the object is properly initialized and the symbolic link it
196	  refers to is an absolute link,
197	- \c false, otherwise.
198*/
199bool
200BSymLink::IsAbsolute()
201{
202	char contents[B_PATH_NAME_LENGTH];
203	bool result = (ReadLink(contents, sizeof(contents)) >= 0);
204	if (result)
205		result = BPrivate::Storage::is_absolute_path(contents);
206	return result;
207}
208
209
210void BSymLink::_MissingSymLink1() {}
211void BSymLink::_MissingSymLink2() {}
212void BSymLink::_MissingSymLink3() {}
213void BSymLink::_MissingSymLink4() {}
214void BSymLink::_MissingSymLink5() {}
215void BSymLink::_MissingSymLink6() {}
216
217
218//! Returns the BSymLink's file descriptor.
219/*! To be used instead of accessing the BNode's private \c fFd member directly.
220	\return the file descriptor, or -1, if not properly initialized.
221*/
222int
223BSymLink::get_fd() const
224{
225	return fFd;
226}
227