[BUGFIX] Installer rejects traling slash in link target
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / FolderStructure / LinkNode.php
1 <?php
2 namespace TYPO3\CMS\Install\FolderStructure;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2013 Christian Kuhn <lolli@schwarzbu.ch>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 use TYPO3\CMS\Install\Status;
28
29 /**
30 * A link
31 */
32 class LinkNode extends AbstractNode implements NodeInterface {
33
34 /**
35 * @var string Optional link target
36 */
37 protected $target = '';
38
39 /**
40 * Implement constructor
41 *
42 * @param array $structure Structure array
43 * @param NodeInterface $parent Parent object
44 * @throws Exception\InvalidArgumentException
45 */
46 public function __construct(array $structure, NodeInterface $parent = NULL) {
47 if (is_null($parent)) {
48 throw new \TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException(
49 'Link node must have parent',
50 1380485700
51 );
52 }
53 $this->parent = $parent;
54
55 // Ensure name is a single segment, but not a path like foo/bar or an absolute path /foo
56 if (strstr($structure['name'], '/') !== FALSE) {
57 throw new \TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException(
58 'File name must not contain forward slash',
59 1380546061
60 );
61 }
62 $this->name = $structure['name'];
63
64 if (isset($structure['target']) && $structure['target'] !== '') {
65 $this->target = $structure['target'];
66 }
67 }
68
69 /**
70 * Get own status
71 * Returns information status if running on Windows
72 * Returns OK status if is link and possible target is correct
73 * Else returns error (not fixable)
74 *
75 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
76 */
77 public function getStatus() {
78 if ($this->isWindowsOs()) {
79 $status = new Status\InfoStatus();
80 $status->setTitle($this->getRelativePathBelowSiteRoot() . ' should be a link, but this support is incomplete for windows.');
81 $status->setMessage(
82 'This node is not handled for Windows OS and should be checked manually.'
83 );
84 return array($status);
85 }
86
87 if (!$this->exists()) {
88 $status = new Status\ErrorStatus();
89 $status->setTitle($this->getRelativePathBelowSiteRoot() . ' should be a link, but it does not exist');
90 $status->setMessage('Links can not be fixed by this system');
91 return array($status);
92 }
93
94 if (!$this->isLink()) {
95 $status = new Status\ErrorStatus();
96 $status->setTitle('Path ' . $this->getRelativePathBelowSiteRoot() . ' is not a link');
97 $type = @filetype($this->getAbsolutePath());
98 if ($type) {
99 $status->setMessage(
100 'The target ' . $this->getRelativePathBelowSiteRoot() . ' should be a link,' .
101 ' but is of type ' . $type . '. This can not be fixed. Please investigate.'
102 );
103 } else {
104 $status->setMessage(
105 'The target ' . $this->getRelativePathBelowSiteRoot() . ' should be a file,' .
106 ' but is of unknown type, probably because some upper level directory does not exist. Please investigate.'
107 );
108 }
109 return array($status);
110 }
111
112 if (!$this->isTargetCorrect()) {
113 $status = new Status\ErrorStatus();
114 $status->setTitle($this->getRelativePathBelowSiteRoot() . ' is a link, but link target is not as specified');
115 $status->setMessage(
116 'Link target should be ' . $this->getTarget() . ' but is ' . $this->getCurrentTarget()
117 );
118 return array($status);
119 }
120
121 $status = new Status\OkStatus();
122 $status->setTitle($this->getRelativePathBelowSiteRoot());
123 return array($status);
124 }
125
126 /**
127 * Fix structure
128 *
129 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
130 */
131 public function fix() {
132 $status = new Status\NoticeStatus();
133 $status->setTitle('Fixing link ' . $this->getRelativePathBelowSiteRoot() . ' is not implemented');
134 return array($status);
135 }
136
137 /**
138 * Get link target
139 *
140 * @return string Link target
141 */
142 protected function getTarget() {
143 return $this->target;
144 }
145
146 /**
147 * Find out if node is a link
148 *
149 * @throws Exception\InvalidArgumentException
150 * @return boolean TRUE if node is a link
151 */
152 protected function isLink() {
153 if (!$this->exists()) {
154 throw new \TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException(
155 'Link does not exist',
156 1380556246
157 );
158 }
159 return @is_link($this->getAbsolutePath());
160 }
161
162 /**
163 * Checks if the real link target is identical to given target
164 *
165 * @throws Exception\InvalidArgumentException
166 * @return boolean TRUE if target is correct
167 */
168 protected function isTargetCorrect() {
169 if (!$this->exists()) {
170 throw new \TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException(
171 'Link does not exist',
172 1380556245
173 );
174 }
175 if (!$this->isLink()) {
176 throw new \TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException(
177 'Node is not a link',
178 1380556247
179 );
180 }
181
182 $result = FALSE;
183 $expectedTarget = $this->getTarget();
184 if (empty($expectedTarget)) {
185 $result = TRUE;
186 } else {
187 $actualTarget = $this->getCurrentTarget();
188 if ($actualTarget === rtrim($expectedTarget, '/')) {
189 $result = TRUE;
190 }
191 }
192 return $result;
193 }
194
195 /**
196 * Return current target of link
197 *
198 * @return string target
199 */
200 protected function getCurrentTarget() {
201 return readlink($this->getAbsolutePath());
202 }
203
204 }