mainos/iofs.js
var mainos = {
versionnr: 190,
versionlt: "0CC",
serverpath: "https://maingron.com",
serverroot: "https://maingron.com/projects/MainOS/server",
repository: "https://maingron.com/projects/MainOS/server/repository.json",
creator: "Maingron",
copyright: "Maingron 2018 - 2023"
};
mainos.versionnrstring = "00" + mainos.versionnr;
mainos.version = mainos.versionnr;
var ismainos = 1;
var setting = {}; // deprecated
function listdir(path, listChildren = false) { // List directory // Todo!: add depth parameter
console.warn("IOFS1: listdir(", path , ")");
if(path.slice(-1) != "/") { // Check for trailing slash and add one if not found
path += "/";
}
if(!isfolder(path) && path != "/") { // Return nothing if is not a folder and not requesting rootdir (/)
return;
}
var result = [];
var fileList = Object.keys(localStorage); // Use fileList instead of Object.keys(localStorage), else result might break because files might be added while in a loop
if(path == "/") { // If want to see rootdir ("/")
var rootDirContents = [];
for (var i = 0; i < fileList.length; i++) {
if(fileList[i].slice(0, -1).length <= 3) { // Only show rootdir / all HDDs - allow up to 2 letter-drives (C:/ or AB:/)
if(fileList[i].slice(-1) == "/") { // Make sure to ignore 1-letter-files (C:/t)
rootDirContents.push(fileList[i]); // Push HDD into rootDirContents-Array
}
}
}
fileList = rootDirContents;
return fileList; // Return HDD list; We're assuming nothing is wrong with the list and skip the actual folder scanning part below
}
for (var i = 0; i < fileList.length; i++) { // Do for ALL files
var myNowFile = fileList[i];
if(myNowFile.includes(path)) { // Only work on Files / Folders within path
if(myNowFile.split(path)[1].includes("/")) {
if(myNowFile.split(path)[1].split("/")[1].length > 1) {
} else {
result.push(myNowFile); // Return folders
}
} else {
result.push(myNowFile); // Return files
}
}
}
for(var i = 0; i < result.length; i++) { // Remove requested-path (The folder we're asking for) entry from final result in this loop
if(result[i] == path) { // If entry == requested-path
if(result[i] != result[0]) { // Make sure not to clone the requested-path entry instead if it happens to be on entry 0
result[i] = result[0]; // Take entry 0 and put it into requested-path entry
result.shift(); // Remove the now duplicated entry
} else {
result[i] = result[result.length - 1]; // Take last entry and put it into requested-path entry
result.pop(); // Remove the now duplicated entry
}
}
}
result = result.sort(); // Apply some bit of sorting - better than nothing but definitely space to be improved
if(listChildren) { // If requested to list children, recursively run listdir on all children. Append their paths to the result array
for(var i = 0; i < result.length; i++) {
if(isfolder(result[i])) {
var myChildren = listdir(result[i], true);
for(var j = 0; j < myChildren.length; j++) {
result.push(myChildren[j]);
}
}
}
}
return result;
}
function loadfile(path,requestattributes = false) {
console.warn("IOFS1: loadfile(", path, requestattributes , ")");
const myFile = localStorage.getItem(path);
// if (localStorage.getItem(path).length < 2 || localStorage.getItem(path).indexOf("*") < 5) { // TODO: Check what this save thing does - probably can be removed
// savefile(path, localStorage.getItem(path));
// }
if(myFile != null && myFile != "undefined") { // If file exists
// TODO: This was probably supposed to be some kind of shortcut loader. It was messing up stuff and now it needs to be checked and reimplemented
// if(myFile.indexOf("loadfile(") > -1) {
// if(myFile.indexOf("loadfile('") > -1) {
// return(loadfile(myFile.split("loadfile('")[1].split("')")[0].toString()));
// } else if(myFile.indexOf("loadfile(\"")> -1) {
// return(loadfile(myFile.split("loadfile(\"")[1].split("\")")[0].toString()));
// }
// }
if(requestattributes == 1) { // Return only file attributes if requested
var myLoadResult = myFile.split("*")[0];
if(myLoadResult.includes("d=")) { // only if file has a date
// - We have to expand the timestamp again, since we removed important parts of it when saving
let myLoadResultDate = myLoadResultDateOld = myLoadResult.split("d=")[1].split(",")[0];
myLoadResultDate = dateCompression(false, myLoadResultDate);
myLoadResult = myLoadResult.replace(myLoadResultDateOld, myLoadResultDate);
}
return myLoadResult;
} else {
return myFile.split("*")[1];
}
} else {
return myFile;
}
}
function isfile(path) {
console.warn("IOFS1: isfile(", path , ")");
const myFile = localStorage.getItem(path)
if (myFile == null || myFile == "undefined") {
return false;
} else {
return true;
}
}
function isfolder(path) {
console.warn("IOFS1: isfolder(", path , ")");
if(!path.endsWith("/")) { // Add trailing slash if not present
path += "/";
}
const myFile = localStorage.getItem(path)
if(myFile == null || myFile == "undefined") { // If file or folder doesn't exist
return false;
} else {
if(loadfile(path,1).includes("t=dir") || loadfile(path,1).includes("t=d")) { // If attributes of path equal type=dir
return true;
} else {
return false;
}
}
}
function isnofile(path) { // Todo: Check if should be depreciated
console.warn("IOFS1: isnofile(", path , ")");
if (isfile(path)) {
return false;
} else {
return true;
}
}
/**
* Returns the compressed / decompressed date of the input date
* @param {boolean} gets compressed if true, decompressed if false
* @param {Date} date Date to compress / decompress
* @returns {number} Compressed / decompressed date
**/
function dateCompression(compress = false, date = new Date()) {
console.warn("IOFS1: dateCompression(", compress, date , ")");
if(compress == true) { // apply compression
// if not a date, make it one
if(typeof date != "object") {
date = new Date(date);
}
date = (date.getTime() - date.getMilliseconds()) / 1000; // Save without milliseconds to save about 3 bytes per file
date -= 1000000000; // Remove this value to save up to 1 byte per file. Won't save storage after the year 2033
} else { // compress == false -> decompress
date = +date + 1000000000;
date = date + "000";
}
return +date;
}
function savefile(path, content, override, attr) {
console.warn("IOFS1: savefile(", path, content, override, attr , ")");
if (!attr || attr.includes("d=") == false) {
var mySaveDate = new Date();
mySaveDate = (mySaveDate.getTime() - mySaveDate.getMilliseconds()) / 1000; // Save without milliseconds to save about 3 bytes per file
mySaveDate -= 1000000000; // Remove this value to save up to 1 byte per file. Won't save storage after the year 2033
attr = "d=" + mySaveDate + "," + attr; // Todo: Make the date footprint as small as possible
} else if(attr && attr.includes("t=dir")) {
if(path.slice(-1) != "/") { // Check for trailing slash
console.warn("Directories are supposed to have a trailing slash. Saving: " + path + ".");
path += "/";
}
}
if (override == "undefined" || override == "null") {
override = 0;
}
if (!override && isfile(path)) {
return false;
} else {
localStorage.setItem(path, attr + "*" + content);
}
return true;
}
function savedir(path, createParentStructure = true, attributes = "t=d") {
console.warn("IOFS1: savedir(", path, createParentStructure, attributes , ")");
if(path.charAt(path.length - 1) != "/") {
path += "/"; // Append trailing slash, if there is none
}
if(isfile(path)) { return false; } // If file exists, return false
// if attributes don't include type, add it
if(!attributes.includes("t=d")) {
attributes += ",t=d";
}
var myPathArray = path.split("/");
var fullParentFolderPath = path.split(myPathArray[myPathArray.length - 2])[0]; // Get full path of parent folder
if(createParentStructure) {
var myPath = "";
for(var i = 0; i < myPathArray.length - 1; i++) {
myPath += myPathArray[i] + "/";
if(!isfolder(myPath)) {
savefile(myPath, "", 0, attributes);
}
}
} else if(!isfolder(fullParentFolderPath)) { // If parent folder doesn't exist
return "Error: Parent folder doesn't exist";
}
return savefile(path, "", 0, attributes);
}
function deletefile(path, includeChildren = false) { // Delete a file or folder
console.warn("IOFS1: deletefile(", path, includeChildren , ")");
// check if file or folder exists, else return error
if(!isfile(path) && !isfolder(path)) {
return "Error: File or folder doesn't exist";
}
// if deleting a folder, delete all files in it
if(isfolder(path) && includeChildren) {
var myDirList = listdir(path, 1);
for(var i = 0; i < myDirList.length; i++) {
deletefile(myDirList[i], 1);
}
} else if(isfolder(path) && !includeChildren) {
return "Error: Can't delete folder without including children";
}
localStorage.removeItem(path);
}
function getFilename(path) { // This returns the filename and removes the full path ("C:/users/testuser/test.txt" -> "test.txt")
console.warn("IOFS1: getFilename(", path , ")");
var myResult;
if(isfolder(path)) {
myResult = path.split("/")[path.split("/").length - 2]; // Return this if is folder
} else {
myResult = path.split("/")[path.split("/").length - 1]; // Return this if is file
}
return myResult;
}
function copyFile(source, destination, doOverride = false) {
console.warn("IOFS1: copyFile(", source, destination, doOverride , ")");
// WIP
if(isfile(source) && !isfolder(source)) { // If source file does exist and is NOT a folder (for now)
savefile(destination, loadfile(source), doOverride, loadfile(source, true));
return true;
} else {
return false;
}
}
/**
* Copies an folder and its contents to destination
* @param {String} source
* @param {String} destination
* @param {boolean} doOverride
* @param {boolean} doCopyAttributes
* @returns {boolean} Returns true if successful, false if not
*/
function copyFolder(source, destination, doOverride = false, doCopyAttributes = true) {
console.warn("IOFS1: copyFolder(", source, destination, doOverride, doCopyAttributes , ")");
if(isfolder(destination) && !doOverride) {
return false;
}
var directoryList = listdir(source, true);
savedir(destination, false, loadfile(source, true)); // Copy source folder itself and its attributes
for(entry of directoryList) {
if(isfolder(entry)) {
savedir(destination + entry.split(source)[1], false, loadfile(entry, true));
} else {
copyFile(entry, destination + entry.split(source)[1], doOverride);
}
}
return true;
}
/**
* Returns the size of a file in bytes
* @param {String} path Path to file
* @param {boolean} requestattributes returns either the size of file attributes or only the size of the file content
* @returns {number} File size in bytes
*/
function getFileSize(path, requestattributes = false) {
console.warn("IOFS1: getFileSize(", path, requestattributes , ")");
return +loadfile(path, requestattributes).length;
}
function moveFile(source, destination) {
console.warn("IOFS1: moveFile(", source, destination , ")");
// WIP
}
/**
* Returns the foldername of a path
* @param {String} path Path to file or folder
* @returns {String} Foldername
* @example
* // returns "testuser"
* getFoldername("C:/users/testuser/test.txt");
* @example
* // returns "testuser"
* getFoldername("C:/users/testuser/");
*/
function getFoldername(path) {
console.warn("IOFS1: getFoldername(", path , ")");
let result;
// add trailing slash if not present and is folder
if(path.slice(-1) != "/" && isfolder(path)) {
path += "/";
}
result = path.split("/")[path.split("/").length - 2]; // Return this if is folder
return result;
}
/**
* Lists attributes of a folder / file in an array
* @param {String} path Path to file or folder
* @returns {Array} Array of attributes
*/
function getAttributes(path) {
console.warn("IOFS1: getAttributes(", path , ")");
return loadfile(path, true).split(",");
}
/**
* Returns the value of an attribute of a file / folder
* @param {String} path Path to file or folder
* @param {String} attribute Attribute to get
* @returns {String} Value of attribute
*/
function getAttribute(path, attribute) {
console.warn("IOFS1: getAttribute(", path, attribute , ")");
var myAttributes = getAttributes(path);
for(iAttribute of myAttributes) {
if(iAttribute.split("=")[0] == attribute) {
return iAttribute.split("=")[1];
}
}
return false;
}
/**
* sets attributes of a file / folder
* @param {String} path Path to file or folder
* @param {String} attribute Attribute to set
* @param {String} value Value to set attribute to
**/
function setAttribute(path, attribute, value) {
console.warn("IOFS1: setAttribute(", path, attribute, value , ")");
var myAttributes = getAttributes(path);
var myNewAttributes = "";
if(attribute == "d") { // if attribute is date, compress it
value = dateCompression(true, value);
}
for(var i = 0; i < myAttributes.length; i++) {
if(myAttributes[i].split("=")[0] == attribute) {
myNewAttributes += attribute + "=" + value + ",";
} else {
myNewAttributes += myAttributes[i] + ",";
}
}
// if attribute doesn't exist, add it
if(!myNewAttributes.includes(attribute)) {
myNewAttributes += attribute + "=" + value + ",";
}
myNewAttributes = myNewAttributes.slice(0, -1);
savefile(path, loadfile(path).split("*")[1], 1, myNewAttributes);
}
function formatfs(sure, reload = true) { // Todo: Update
console.warn("IOFS1: formatfs(", sure, reload , ")");
if (sure == "yes") {
localStorage.clear();
if(reload) {
window.location.reload();
} else {
savefile = undefined;
savedir = undefined;
loadfile = undefined;
document.title += " - Frozen (Formatted; Waiting)";
document.body.innerHTML = /*html*/`
<center>
<br>
<br>
<h1>${system.osDetails.name} formatted; Frozen until restart</h1>
<br>
<button onclick="window.location.reload();">Restart</button>
</center>
`;
Object.freeze(mainos = undefined);
Object.freeze(setting = undefined);
Object.freeze(program = undefined);
Object.freeze(appdata = undefined);
Object.freeze(system = undefined);
}
}
}
if (!iofs.exists("C:/mainos/system32/ExpectedVersionnr.txt") || iofs.load("C:/mainos/system32/ExpectedVersionnr.txt") < mainos.versionnr) {
document.write("<script src=\"mainos/createiofs.js\"></script>");
}