zen-fs / core

A filesystem, anywhere.
https://zenfs.dev/core/
MIT License
134 stars 20 forks source link

FS copying to folder issue #97

Closed chinonso098 closed 3 months ago

chinonso098 commented 3 months ago

Hi there

I am experiencing as strange issue where copying to some folders work perfectly, copying to another folder doesn't. But these folders are present. The osdrive folder is what was used to generate the index.json file.

osdrive-image

Screenshot 2024-08-04 at 8 29 00 AM Screenshot 2024-08-04 at 8 41 00 AM

If a give a command to copy simple.txt to /Desktop, it works perfectly

Screenshot 2024-08-04 at 8 11 29 AM

result and console log

Screenshot 2024-08-04 at 8 12 51 AM

if I issues that command to copy simple.txt to /Documents, it throws and error

Screenshot 2024-08-04 at 8 20 51 AM

It saying it can't find it.

james-pre commented 3 months ago

@chinonso098,

Thanks for opening an issue. Could you please convert all terminal/console screenshots into code blocks? For example:

>: example-command
Example output

(You can edit your initial comment)

Also, if you are using the callbacks API, I recommend switching to the Promises API, since the callback API acts only as a wrapper for the Promises API, and using fs.promises will make debugging easier. Note the syntax is:

// for async functions
async function example1() {
    await fs.promises.copyFile(...);
}

// for normal functions
function example2() {
    fs.promises.copyFile(...)
        .then(result => { ... })
        .catch(error => { ... });
}

You don't have to catch errors from a Promise. If you don't, it will throw a normal error. I strongly recommend you use async/await syntax since it is much cleaner and easier to debug.

chinonso098 commented 3 months ago

Here is my current CopyFileAsync method that cp calls.

public async copyFileAsync(sourcepath:string, destinationpath:string):Promise<boolean>{

        const fileName = this.getFileName(sourcepath);
        console.log(`Destination: ${destinationpath}/${fileName}`);
        return new Promise<boolean>((resolve, reject) =>{
             fs.readFile(sourcepath,(err, contents = Buffer.from('')) =>{
                if(err){
                    console.log('copyFileAsync error:',err)
                    reject(false)
                }else{
                    fs.writeFile(`${destinationpath}/${fileName}`, contents, {flag: 'wx'}, (err) =>{  
                        if(err?.code === 'EEXIST' ){
                            console.log('copyFileAsync Error: file already exists',err);

                            // if file exists, increment it simple.txt, simple(1).txt ...
                            const itrName = this.iterateFileName(`${destinationpath}/${fileName}`);
                            fs.writeFile(itrName,contents,(err) =>{  
                                if(err){
                                    console.log('copyFileAsync Iterate Error:',err);
                                    reject(false);
                                }
                                resolve(true);
                            });
                        }else{
                            console.log('copyFileAsync Error:',err);
                            this._fileExistsMap.set(`${destinationpath}/${fileName}`,0);
                            resolve(true);
                        }
                    });
                }
            });
        });
    }

Let me give the fs.promises.... at try

chinonso098 commented 3 months ago

I re-wrote the function using fs.promises, but the issues still persists

    public async copyFileAsync(sourcePath: string, destinationPath: string): Promise<boolean> {
        const fileName = this.getFileName(sourcePath);
        console.log(`Destination: ${destinationPath}/${fileName}`);
        return await fs.promises
            .readFile(sourcePath)
            .then(async (result) => {
                await fs.promises
                    .writeFile(`${destinationPath}/${fileName}`, result, { flag: 'wx' })
                    .then(() => {
                        console.log('file succesfully written');
                        this._fileExistsMap.set(`${destinationPath}/${fileName}`, 0);
                    })
                    .catch((err) => {
                        console.log(`error: ${err} ---------- error code:${err.code}`);

                        if (err?.code === 'EEXIST') {
                            console.log('copyFileAsync Error: file already exists', err);

                            // if file exists, increment it simple.txt, simple(1).txt ...
                            const itrName = this.iterateFileName(`${destinationPath}/${fileName}`);
                            /**..... */
                        }
                    });
                return true;
            })
            .catch((err) => {
                console.log('copyFileAsync readFile:', err);
                return false;
            });
    }

Console output

Screenshot 2024-08-04 at 1 13 18 PM
james-pre commented 3 months ago

Your rewrite to use fs.promises is incorrect. I strongly recommend you read the documentation for async and await. The docs should give you an idea on how to correctly use async/await syntax.

Second, It is very difficult to help you when your code and such is in screenshots. Please copy and paste your code, console, and terminal into code blocks. (not quotes).

james-pre commented 3 months ago

@chinonso098,

Also, Is there any reason you are using readFile and writeFile instead of copyFile, or better yet cp?

chinonso098 commented 3 months ago

Much of the file-service code, is a carryover from BrowserFS. BrowserFS did not have a copyFile method. Hence the readFile and writeFile. Also, my mind din't think to check for a copyFile method, and the code example you gave above, didn't register at the time..

I have now switched to using the copyFile method, and the result is the same.

james-pre commented 3 months ago

@chinonso098,

As I already mentioned, could you please convert all terminal/console screenshots into code blocks? As is, It is too difficult to discern the text in many of the images you sent. If you can send the console/terminal input and output in code blocks, I can help you more.

chinonso098 commented 3 months ago

Let me keep wrestling with it, and see what happens. I'll figure something out. Again thanks for your time and assistance.

james-pre commented 3 months ago

@chinonso098 No problem! Please let me know if you have any issues with ZenFS.

chinonso098 commented 3 months ago

@james-pre Can I furnish you with the project repo so that you can run it and see what I'm seeing ? It has the FS, the index.json and everything wired up. you'll only have to issue copy commands from the the terminal, and you can put a break-point on the CopyFileAsync() method in file.services.ts

james-pre commented 3 months ago

@chinonso098,

You mean https://github.com/chinonso098/CheetahOS? I can take a look at it.

chinonso098 commented 3 months ago

Yes, this branch to be exact: https://github.com/chinonso098/CheetahOS/tree/10001_New_FileSystem_Impl

you can ignore the code setup in the ReadMe. That was pertaining to BrowserFS.

in the terminal app

cp /simple.txt /Desktop ---- this works

cp /simple.txt /Documents ----- this fails

Thanks for the Assist

james-pre commented 2 months ago

@chinonso098,

Thanks for being patient.

I've made a reproduction, which essentially is the stripped code for doing only what should make the bug trigger, in addition to some things for debugging.

It looks like you fail to call the initialization function when executing the copy command, which triggers an ENOENT on the first copy.

If it does get called though, I get some strange behavior:


Virtual FS shell.
Available commands: help, ls, cp, cd, mv, rm, cat, stat, pwd, exit/quit
Run "default" to attempt bug reproduction.

/$ ls
Desktop Documents Downloads simple.txt
/$ cp simple.txt .
Copying to: ./simple.txt
Copy simple.txt -> . succeeded
/$ default
> cp /simple.txt /Desktop
Copying to: /Desktop/simple.txt
Error: ENOENT: No such file or directory, '/Desktop'
> cp /simple.txt /Documents
Copying to: /Documents/simple.txt
Error: ENOENT: No such file or directory, '/Documents'
> ls Desktop
desktop.txt
> ls Documents
Credits.md
/$ exit
Exiting...

screenshot

I'm not entirely sure what is causing this issue, though I will definitely take a closer look.

If you would like to check it out:

git clone https://github.com/zen-fs/core-repro-97
cd core-repro-97
npm install
npm run test
chinonso098 commented 2 months ago

Hi, @james-pre. Thanks for getting back to me

The ZenFS Initilization(), is one the first things to run (it is called by getEntriesFromDirectoryAsync() in file.services.ts).

It is what allows for the icons on the Desktop to be displayed. I launch the Terminal App from the Desktop.

Hence, why I was confused why

cp simple.txt /Desktop -- successful. And immediately after, I try

cp simple.txt /Documents -- failed .

Sure I will test core-repro-97.

Thanks for the assist