blob: 52b2205f40c6d197e07f924776e7b98c31884ec2 [file] [log] [blame]
William Wilgus9daacab2022-03-03 07:37:03 -05001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2017 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
22#include <errno.h>
23#include "fileobj_mgr.h"
24#include "rb_namespace.h"
25#include "file_internal.h"
William Wilgusfdc36682024-03-21 18:27:23 -040026#include <stdio.h> /*snprintf*/
William Wilgus9daacab2022-03-03 07:37:03 -050027
William Wilgusa5c16d22022-03-15 00:45:00 -040028/* Define LOGF_ENABLE to enable logf output in this file */
29//#define LOGF_ENABLE
30#include "logf.h"
31
32#if !defined(HAVE_MULTIVOLUME) && defined(LOGF_ENABLE)
33 int volume = 0;
34#endif
35
36
William Wilgus9daacab2022-03-03 07:37:03 -050037#define ROOT_CONTENTS_INDEX (NUM_VOLUMES)
38#define NUM_ROOT_ITEMS (NUM_VOLUMES+1)
39
40static uint8_t root_entry_flags[NUM_VOLUMES+1];
41static struct file_base_binding *root_bindp;
42
43static inline unsigned int get_root_item_state(int item)
44{
45 return root_entry_flags[item];
46}
47
48static inline void set_root_item_state(int item, unsigned int state)
49{
50 root_entry_flags[item] = state;
51}
52
53static void get_mount_point_entry(IF_MV(int volume,) struct DIRENT *entry)
54{
55#ifdef HAVE_MULTIVOLUME
56 get_volume_name(volume, entry->d_name);
57#else /* */
58 strcpy(entry->d_name, PATH_ROOTSTR);
59#endif /* HAVE_MULTIVOLUME */
60#if defined(_FILESYSTEM_NATIVE_H_)
61 entry->info.attr = ATTR_MOUNT_POINT;
62 entry->info.size = 0;
63 entry->info.wrtdate = 0;
64 entry->info.wrttime = 0;
65#endif /* is dirinfo_native */
William Wilgusa5c16d22022-03-15 00:45:00 -040066 logf("%s: vol:%d, %s", __func__, volume, entry->d_name);
William Wilgus9daacab2022-03-03 07:37:03 -050067}
68
69/* unmount the directory that enumerates into the root namespace */
70static void unmount_item(int item)
71{
72 unsigned int state = get_root_item_state(item);
William Wilgusa5c16d22022-03-15 00:45:00 -040073 logf("%s: state: %u", __func__, state);
William Wilgus9daacab2022-03-03 07:37:03 -050074 if (!state)
75 return;
76
77 if (state & NSITEM_CONTENTS)
78 {
79 fileobj_unmount(root_bindp);
80 root_bindp = NULL;
81 }
82
83 set_root_item_state(item, 0);
84}
85
William Wilgusfdc36682024-03-21 18:27:23 -040086static char *root_realpath_internal(void)
87{
88 static char root_realpath[ROOT_MAX_REALPATH];
89 return root_realpath;
90}
91const char* root_get_realpath(void)
92{
93 return root_realpath_internal();
94}
95
William Wilgus9daacab2022-03-03 07:37:03 -050096/* mount the directory that enumerates into the root namespace */
97int root_mount_path(const char *path, unsigned int flags)
98{
William Wilgusfdc36682024-03-21 18:27:23 -040099 const char *folder = NULL; /* is a folder enumerated in the root? */
William Wilgus9daacab2022-03-03 07:37:03 -0500100#ifdef HAVE_MULTIVOLUME
William Wilgusfdc36682024-03-21 18:27:23 -0400101 int volume = path_strip_volume(path, &folder, false);
William Wilgus9daacab2022-03-03 07:37:03 -0500102 if (volume == ROOT_VOLUME)
103 return -EINVAL;
William Wilgus9daacab2022-03-03 07:37:03 -0500104 if (!CHECK_VOL(volume))
105 return -ENOENT;
William Wilgusfdc36682024-03-21 18:27:23 -0400106 char volname[VOL_MAX_LEN+2];
107 make_volume_root(volume, volname);
William Wilgus9daacab2022-03-03 07:37:03 -0500108#else
William Wilgusfdc36682024-03-21 18:27:23 -0400109 const char volname = PATH_ROOTSTR;
William Wilgus9daacab2022-03-03 07:37:03 -0500110 if (!path_is_absolute(path))
William Wilgusa5c16d22022-03-15 00:45:00 -0400111 {
112 logf("Path not absolute %s", path);
William Wilgus9daacab2022-03-03 07:37:03 -0500113 return -ENOENT;
William Wilgusa5c16d22022-03-15 00:45:00 -0400114 }
William Wilgusfdc36682024-03-21 18:27:23 -0400115 path_dirname(path, &folder);
William Wilgus9daacab2022-03-03 07:37:03 -0500116#endif /* HAVE_MULTIVOLUME */
William Wilgus9daacab2022-03-03 07:37:03 -0500117 bool contents = flags & NSITEM_CONTENTS;
William Wilgusfdc36682024-03-21 18:27:23 -0400118 int item = IF_MV_VOL(volume);
William Wilgus9daacab2022-03-03 07:37:03 -0500119 unsigned int state = get_root_item_state(item);
William Wilgusa5c16d22022-03-15 00:45:00 -0400120 logf("%s: item:%d, st:%u, %s", __func__, item, state, path);
William Wilgusfdc36682024-03-21 18:27:23 -0400121 if (contents && state) /* volume must be mounted to enumerate into the root namespace */
William Wilgus9daacab2022-03-03 07:37:03 -0500122 {
William Wilgusfdc36682024-03-21 18:27:23 -0400123 if (get_root_item_state(ROOT_CONTENTS_INDEX))
124 return -EBUSY; /* error something is already enumerated */
William Wilgus9daacab2022-03-03 07:37:03 -0500125 /* cache information about the target */
126 struct filestr_base stream;
127 struct path_component_info compinfo;
William Wilgus9daacab2022-03-03 07:37:03 -0500128 int e = errno;
129 int rc = open_stream_internal(path, FF_DIR | FF_PROBE | FF_INFO |
130 FF_DEVPATH, &stream, &compinfo);
131 if (rc <= 0)
132 {
133 rc = rc ? -errno : -ENOENT;
134 errno = e;
135 return rc;
136 }
William Wilgus9daacab2022-03-03 07:37:03 -0500137 if (!fileobj_mount(&compinfo.info, FO_DIRECTORY, &root_bindp))
138 return -EBUSY;
William Wilgusfdc36682024-03-21 18:27:23 -0400139 int root_state = NSITEM_MOUNTED | (flags & (NSITEM_HIDDEN|NSITEM_CONTENTS));
140 set_root_item_state(ROOT_CONTENTS_INDEX, root_state);
141 flags |= state; /* preserve the state of the mounted volume */
142 if (!folder)
143 {
144 folder = "";
145 }
146 else
147 {
148 /*if a folder has been enumerated don't mark the whole volume */
149 if (folder[0] != '\0' && folder[1] != '\0')
150 flags &= ~NSITEM_CONTENTS;
William Wilgus9daacab2022-03-03 07:37:03 -0500151
William Wilgusfdc36682024-03-21 18:27:23 -0400152 }
153 snprintf(root_realpath_internal(), ROOT_MAX_REALPATH,"%s%s", volname, folder);
154 }
155 else if (state) /* error volume already mounted */
156 return -EBUSY;
William Wilgus9daacab2022-03-03 07:37:03 -0500157 state = NSITEM_MOUNTED | (flags & (NSITEM_HIDDEN|NSITEM_CONTENTS));
158 set_root_item_state(item, state);
William Wilgus9daacab2022-03-03 07:37:03 -0500159 return 0;
160}
161
William Wilgusfdc36682024-03-21 18:27:23 -0400162/* check if volume in path is mounted in the root namespace */
163bool ns_volume_is_visible(IF_MV_NONVOID(int volume))
164{
165 int item = IF_MV_VOL(volume);
166 if ((item == ROOT_VOLUME) || !CHECK_VOL(item))
167 return false;
168 unsigned int state = get_root_item_state(item);
169 return state && (((state & NSITEM_HIDDEN) == 0) || (state & NSITEM_CONTENTS));
170}
171
William Wilgus9daacab2022-03-03 07:37:03 -0500172/* inform root that an entire volume is being unmounted */
173void root_unmount_volume(IF_MV_NONVOID(int volume))
174{
William Wilgusa5c16d22022-03-15 00:45:00 -0400175 logf("%s: vol: %d", __func__, volume);
William Wilgus9daacab2022-03-03 07:37:03 -0500176 FOR_EACH_VOLUME(volume, item)
177 {
178 #ifdef HAVE_MULTIVOLUME
179 uint32_t state = get_root_item_state(item);
180 if (state && (volume < 0 || item == volume))
181 #endif /* HAVE_MULTIVOLUME */
182 unmount_item(item);
183 }
184
185 /* if the volume unmounted contains the root directory contents then
186 the contents must also be unmounted */
187#ifdef HAVE_MULTIVOLUME
188 uint32_t state = get_root_item_state(ROOT_CONTENTS_INDEX);
189 if (state && (volume < 0 || BASEINFO_VOL(&root_bindp->info) == volume))
190#endif
William Wilgusfdc36682024-03-21 18:27:23 -0400191 {
William Wilgus9daacab2022-03-03 07:37:03 -0500192 unmount_item(ROOT_CONTENTS_INDEX);
William Wilgusfdc36682024-03-21 18:27:23 -0400193 root_realpath_internal()[0] = '\0';
194 }
William Wilgus9daacab2022-03-03 07:37:03 -0500195}
196
197/* parse the root part of a path */
198int ns_parse_root(const char *path, const char **pathp, uint16_t *lenp)
199{
William Wilgusa5c16d22022-03-15 00:45:00 -0400200 logf("%s: path: %s", __func__, path);
William Wilgus9daacab2022-03-03 07:37:03 -0500201 int volume = ROOT_VOLUME;
202
203#ifdef HAVE_MULTIVOLUME
204 /* this seamlessly integrates secondary filesystems into the
205 root namespace (e.g. "/<0>/../../<1>/../foo/." :<=> "/foo") */
206 const char *p;
207 volume = path_strip_volume(path, &p, false);
208 if (volume != ROOT_VOLUME && !CHECK_VOL(volume))
William Wilgusa5c16d22022-03-15 00:45:00 -0400209 {
210 logf("vol: %d is not root", volume);
William Wilgus9daacab2022-03-03 07:37:03 -0500211 return -ENOENT;
William Wilgusa5c16d22022-03-15 00:45:00 -0400212 }
William Wilgus9daacab2022-03-03 07:37:03 -0500213#endif /* HAVE_MULTIVOLUME */
214
215 /* set name to start at last leading separator; name of root will
216 * be returned as "/", volume specifiers as "/<fooN>" */
217 *pathp = GOBBLE_PATH_SEPCH(path) - 1;
218 *lenp = IF_MV( volume < NUM_VOLUMES ? p - *pathp : ) 1;
William Wilgusa5c16d22022-03-15 00:45:00 -0400219#ifdef LOGF_ENABLE
220 if (volume == INT_MAX)
221 logf("vol: ROOT(%d) %s", volume, *pathp);
222 else
223 logf("vol: %d %s", volume, *pathp);
224#endif
William Wilgus9daacab2022-03-03 07:37:03 -0500225#ifdef HAVE_MULTIVOLUME
226 if (*lenp > MAX_COMPNAME+1)
William Wilgusa5c16d22022-03-15 00:45:00 -0400227 {
228 logf("%s: path too long %s", __func__, path);
William Wilgus9daacab2022-03-03 07:37:03 -0500229 return -ENAMETOOLONG;
William Wilgusa5c16d22022-03-15 00:45:00 -0400230 }
William Wilgus9daacab2022-03-03 07:37:03 -0500231#endif
William Wilgusa5c16d22022-03-15 00:45:00 -0400232#ifdef LOGF_ENABLE
233 if (volume == INT_MAX)
234 logf("%s: vol: ROOT(%d) path: %s", __func__, volume, path);
235 else
236 logf("%s: vol: %d path: %s", __func__, volume, path);
237#endif
William Wilgus9daacab2022-03-03 07:37:03 -0500238 return volume;
239}
240
241/* open one of the items in the root */
242int ns_open_root(IF_MV(int volume,) unsigned int *callflagsp,
243 struct file_base_info *infop, uint16_t *attrp)
244{
245 unsigned int callflags = *callflagsp;
246 bool devpath = !!(callflags & FF_DEVPATH);
247#ifdef HAVE_MULTIVOLUME
248 bool sysroot = volume == ROOT_VOLUME;
249 if (devpath && sysroot)
250 return -ENOENT; /* devpath needs volume spec */
251#else
252 bool sysroot = !devpath; /* always sysroot unless devpath */
253#endif
254
255 int item = sysroot ? ROOT_CONTENTS_INDEX : IF_MV_VOL(volume);
256 unsigned int state = get_root_item_state(item);
William Wilgusa5c16d22022-03-15 00:45:00 -0400257 logf("%s: Vol:%d St:%d", __func__, item, state);
William Wilgus9daacab2022-03-03 07:37:03 -0500258 if (sysroot)
259 {
260 *attrp = ATTR_SYSTEM_ROOT;
261
262 if (state)
263 *infop = root_bindp->info;
264 else
William Wilgusa5c16d22022-03-15 00:45:00 -0400265 {
266 logf("%s: SysRoot Vol:%d St:%d NOT mounted", __func__, item, state);
William Wilgus9daacab2022-03-03 07:37:03 -0500267 *callflagsp = callflags | FF_NOFS; /* contents not mounted */
William Wilgusa5c16d22022-03-15 00:45:00 -0400268 }
William Wilgus9daacab2022-03-03 07:37:03 -0500269 }
270 else
271 {
272 *attrp = ATTR_MOUNT_POINT;
273
274 if (!devpath && !state)
275 return -ENOENT; /* regular open requires having been mounted */
276#if CONFIG_PLATFORM & PLATFORM_NATIVE
277 if (fat_open_rootdir(IF_MV(volume,) &infop->fatfile) < 0)
William Wilgusa5c16d22022-03-15 00:45:00 -0400278 {
279 logf("%s: DevPath Vol:%d St:%d NOT mounted", __func__, item, state);
William Wilgus9daacab2022-03-03 07:37:03 -0500280 return -ENOENT; /* not mounted */
William Wilgusa5c16d22022-03-15 00:45:00 -0400281 }
William Wilgus9daacab2022-03-03 07:37:03 -0500282#endif
283 get_rootinfo_internal(infop);
284 }
285
286 return 0;
287}
288
289/* read root directory entries */
290int root_readdir_dirent(struct filestr_base *stream,
291 struct ns_scan_info *scanp, struct DIRENT *entry)
292{
293 int rc = 0;
294
295 int item = scanp->item;
William Wilgusa5c16d22022-03-15 00:45:00 -0400296 logf("%s: item: %d", __func__, item);
William Wilgus9daacab2022-03-03 07:37:03 -0500297
298 /* skip any not-mounted or hidden items */
299 unsigned int state;
300 while (1)
301 {
302 if (item >= NUM_ROOT_ITEMS)
303 goto file_eod;
304
305 state = get_root_item_state(item);
306 if ((state & (NSITEM_MOUNTED|NSITEM_HIDDEN)) == NSITEM_MOUNTED)
William Wilgusa5c16d22022-03-15 00:45:00 -0400307 {
William Wilgusfdc36682024-03-21 18:27:23 -0400308#if 1 /* hide the volume enumerated into the root namespace */
309 if (item == ROOT_CONTENTS_INDEX || (state & NSITEM_CONTENTS) == 0)
310 {
311 logf("Found mounted item: %d %s", item, entry->d_name);
312 break;
313 }
314#endif
William Wilgusa5c16d22022-03-15 00:45:00 -0400315 }
William Wilgus9daacab2022-03-03 07:37:03 -0500316
317 item++;
318 }
319
320 if (item == ROOT_CONTENTS_INDEX)
321 {
322 rc = readdir_dirent(stream, &scanp->scan, entry);
323 if (rc < 0)
324 FILE_ERROR(ERRNO, rc * 10 - 1);
325
326 if (rc == 0)
William Wilgusa5c16d22022-03-15 00:45:00 -0400327 {
328 logf("Found root item: %d %s", item, entry->d_name);
William Wilgus9daacab2022-03-03 07:37:03 -0500329 item++;
William Wilgusa5c16d22022-03-15 00:45:00 -0400330 }
William Wilgus9daacab2022-03-03 07:37:03 -0500331 }
332 else
333 {
334 get_mount_point_entry(IF_MV(item,) entry);
335 item++;
336 rc = 1;
William Wilgusa5c16d22022-03-15 00:45:00 -0400337 logf("Found mp item:%d %s", item, entry->d_name);
William Wilgus9daacab2022-03-03 07:37:03 -0500338 }
339
340 scanp->item = item;
341
342file_eod:
343#ifdef HAVE_DIRCACHE
344 if (rc == 0)
345 empty_dirent(entry);
346#endif
347file_error:
William Wilgusa5c16d22022-03-15 00:45:00 -0400348 logf("%s: status: %d", __func__, rc);
William Wilgus9daacab2022-03-03 07:37:03 -0500349 return rc;
350}
351
352/* opens a stream to enumerate items in a namespace container */
353int ns_open_stream(const char *path, unsigned int callflags,
354 struct filestr_base *stream, struct ns_scan_info *scanp)
355{
William Wilgusa5c16d22022-03-15 00:45:00 -0400356 logf("%s: path: %s", __func__, path);
William Wilgus9daacab2022-03-03 07:37:03 -0500357 /* stream still needs synchronization even if we don't have a stream */
358 static struct mutex no_contents_mtx SHAREDBSS_ATTR;
359
360 int rc = open_stream_internal(path, callflags, stream, NULL);
361 if (rc < 0)
362 FILE_ERROR(ERRNO, rc * 10 - 1);
363
364 scanp->item = rc > 1 ? 0 : -1;
365
366 if (stream->flags & FDO_BUSY)
367 {
368 /* root contents are mounted */
369 fat_rewind(&stream->fatstr);
370 }
371 else
372 {
373 /* root contents not mounted */
374 mutex_init(&no_contents_mtx);
375 stream->mtx = &no_contents_mtx;
376 }
377
378 ns_dirscan_rewind(scanp);
379
380 rc = 0;
381file_error:
382 return rc;
383}