const fs = require('fs') let paths = [] let options = [] for(arg of process.argv.slice(3)){ if(arg.startsWith('--')){ options.push(arg) } else if(arg.startsWith('-')){ for(let option of arg.slice(1)){ options.push('-' + option); } } else{ paths.push(arg) } } if(paths.length == 0){ paths = ['.']; } try{ listFiles(paths[0], options) } catch(e){ switch(e.code){ case "ENOENT": console.error(`path "${paths[0]}" does not exist`); break; default: console.error(`ls: ${e.code}`) } } function listFiles(path, options){ const files = ['.', '..'].concat(fs.readdirSync(paths[0])) const nonHiddenFiles = files.filter(file => file[0] != '.') colorList = JSON.parse(process.env.ls_color) if(options.includes('-l')){ console.log(`total ${options.includes('-a') ? files.length : nonHiddenFiles.length}`) for(let file of options.includes('-a') ? files : nonHiddenFiles){ stats = fs.lstatSync(`${path}/${file}`); mode = stats.mode result = "" let color = [] let defaultColor = "\x1b[0m" let fileType = "-" if(stats.isFile()){ fileType = "-"; if(stats.mode & 00100){ //owner can execute color = colorList.ex ? `\x1b[${colorList.ex[0]}m\x1b[${colorList.ex[1]}m` : "\x1b[0m" } } else if (stats.isDirectory()) { fileType = "d"; color = colorList.di ? `\x1b[${colorList.di[0]}m\x1b[${colorList.di[1]}m` : "\x1b[0m" } else if (stats.isSymbolicLink()){ fileType = "l" color = colorList.ln ? `\x1b[${colorList.ln[0]}m\x1b[${colorList.ln[1]}m` : "\x1b[0m" } result += fileType; permissions = "xwr" for(let i=8;i>=0;i--){ result += parseInt(Math.pow(2,i).toString(2)) & mode ? permissions[i%3] : '-' } if(01000 & mode){ // check sticky bit color = "\x1b[40m\x1b[92m\x1b[7m" } let date = new Date(stats.mtimeMs*1000).toDateString().split(' '); result += ` ${usernameFromUID(stats.uid)}\t${groupnameFromGID(stats.gid)}\t${stats.size}\t${date[2]} ${date[1]}. ${options.includes('--color') ? color : ""}${file}${defaultColor}` console.log(result) } } else{ result = "" const defaultColor = "\x1b[0m"; if(options.includes('--color')){ for(let file of options.includes('-a') ? files : nonHiddenFiles){ stats = fs.lstatSync(`${path}/${file}`); let color = defaultColor if(stats.isDirectory()){ color = colorList.di ? `\x1b[${colorList.di[1]}m\x1b[${colorList.di[0]}m` : defaultColor } else if (stats.isSymbolicLink()){ color = colorList.ln ? `\x1b[${colorList.ln[1]}m\x1b[${colorList.ln[0]}m` : defaultColor } if(01000 & stats.mode){ // check sticky bit color = "\x1b[40m\x1b[92m\x1b[7m" } result += color + file + defaultColor + " "; } console.log(result) }else{ console.log(options.includes('-a') ? files.join(' ') : nonHiddenFiles.join(' ')) } } } function usernameFromUID(uid){ const passwd = fs.readFileSync("/etc/passwd", {encoding: 'utf-8'}).split('\n'); for(let line of passwd){ let lineSplited = line.split(':') if(lineSplited[2] == uid){ return lineSplited[0]; } } return uid } function groupnameFromGID(uid){ const passwd = fs.readFileSync("/etc/passwd", {encoding: 'utf-8'}).split('\n'); for(let line of passwd){ let lineSplited = line.split(':') if(lineSplited[3] == uid){ return lineSplited[0]; } } return uid }