') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Layered file system by jaybosamiya-ms · Pull Request #27 · microsoft/litebox · GitHub
Skip to content

Layered file system - #27

Merged
Jay Bosamiya (Microsoft) (jaybosamiya-ms) merged 16 commits into
mainfrom
jayb/push-pnsltkkypous
Mar 7, 2025
Merged

Layered file system#27
Jay Bosamiya (Microsoft) (jaybosamiya-ms) merged 16 commits into
mainfrom
jayb/push-pnsltkkypous

Conversation

@jaybosamiya-ms

@jaybosamiya-msJay Bosamiya (Microsoft) (jaybosamiya-ms) commented Mar 6, 2025

Copy link
Copy Markdown
Member

This PR implements a layered file system, roughly layered::FileSystem<Upper, Lower> (closes#5).

image

Essentially, a layered filesystem itself doesn't carry or store any of the files, but delegates to each of the the layers. Specifically, this implementation will look for and work with files in the upper layer, unless they don't exist, in which case the lower layer is looked at.

The current design of layering treats the lower layer as read-only and performs copy-on-write semantics for moving to upper layer.

The biggest complexity of this implementation comes from needing to support the deletion of files from the lower layer (without actually changing the lower layer), as well as supporting aliasing (same file opened twice) under the presence of writing. There are tests added for ensuring that the behavior of these are as expected.

Currently, the implementation's largest downside is in its handling of directories and permissions, each of which would be improved by having support for stat in the core FileSystem trait, but I decided that should be a separate PR and not be part of this one. There are relevant TODOs in the code for this. We also would need to handle correct positioning of the "migrated" CoW files, but that would require having support for lseek in the core FileSystem trait; similarly, future update.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Overview

This pull request implements a layered file system that delegates file operations to an upper or lower layer. It introduces tests for layered behavior (e.g. copy‐on‐write and file deletion), adds an auxiliary method to compute path ancestors, and adjusts helper routines to support these changes.

Reviewed Changes

FileDescription
litebox/src/fs/tests.rsAdded tests for layered file system behavior including read, write, and deletion scenarios.
litebox/src/path.rsAdded an increasing_ancestors method for computing path components.
litebox/src/fs/shared.rsModified remove() to return the removed descriptor and added an iter_mut() method.
litebox/src/fs/mod.rsRegistered the new layered module and updated doc comments accordingly.

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Comments suppressed due to low confidence (2)

litebox/src/fs/shared.rs:37

  • Changing the return type of remove() from () to Descriptor might break existing callers. Ensure that this change is intentional and update related documentation where necessary.
pub(crate) fn remove(&mut self, mut fd: FileFd) -> Descriptor {

litebox/src/path.rs:119

  • [nitpick] The logic for appending "/" when the last ancestor has a length > 1 is not immediately clear. Consider adding a clarifying comment to explain its purpose.
if res.last().unwrap().len() > 1 {

Comment threadlitebox/src/path.rs
Comment threadlitebox/src/fs/layered.rs Outdated
Comment threadlitebox/src/fs/layered.rs
Comment threadlitebox/src/fs/layered.rs
Comment threadlitebox/src/fs/layered.rs Outdated
Comment threadlitebox/src/fs/layered.rs Outdated
Comment threadlitebox/src/fs/layered.rs
Comment threadlitebox/src/fs/layered.rs
Comment threadlitebox/src/fs/layered.rs Outdated
Comment threadlitebox/src/fs/layered.rs
Comment threadlitebox/src/fs/layered.rs Outdated
@jaybosamiya-ms

Jay Bosamiya (Microsoft) (jaybosamiya-ms) commented Mar 7, 2025

Copy link
Copy Markdown
MemberAuthor

Note: CI failures are due to #29 being merged into main which changed the interfaces. For now, the migration from lower to upper does not account for offsets, which will be fixed up in a future PR. I'm adding a TODO item for this as a comment.

PS: reads/writes on either lower or upper layer would handle offsets correctly in this implementation: the issue only shows up for migrated files, which is a rarer scenario and requires lseek support, thus I am postponing to a separate PR.

Will merge once CI goes green again.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support a parametric layered FileSystem

4 participants

@jaybosamiya-ms@CvvT@wdcui