Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a method to get file contents #50

Open
tukusejssirs opened this issue May 10, 2022 · 2 comments
Open

Add a method to get file contents #50

tukusejssirs opened this issue May 10, 2022 · 2 comments

Comments

@tukusejssirs
Copy link

I’d like to get contents of a file. I have stumbled upon this SO answer, which works perfectly:

smbclient -E -U $USERNAME //server/sharename $PASSWORD -c 'get \\dir\\file /dev/fd/1'

Could we add a method like readFile()? Subsequently, could we also and an method to writeFile() (different from sendFile() that the contents would be in memory only, not a file)?

@tukusejssirs tukusejssirs changed the title Add a methode to get file contents Add a method to get file contents May 10, 2022
@tukusejssirs
Copy link
Author

tukusejssirs commented May 10, 2022

I tried to create a method to make it work, but I noticed that surround single quotes arround remote and local paths make the command in the OP not working (tested on [email protected] on CentOS 7).

What is the reason for quoting the paths? Spaces and other special characters?

Update

It works only without quotes around paths or using double quotes. It does not work with single quotes.

// These commands work
smbclient -U server -c "get ./file.txt /dev/fd/1" "//1.2.3.4/file" --password p4ss
smbclient -U server -c "get \"./file.txt\" \"/dev/fd/1\"" "//1.2.3.4/file" --password p4ss
smbclient -U server -c 'get "./file.txt" "/dev/fd/1"' "//1.2.3.4/file" --password p4ss

// This command does not work
smbclient -U server -c "get './file.txt' '/dev/fd/1'" "//1.2.3.4/file" --password p4ss

Update 2

I’ve just found out that in order make it work, we need to add {stdio: [0, 1, 2, 3]} to the options of execa() (src).

However, now I have no idea why can’t I save the file contents to variable (it is always output to STDOUT).

@tukusejssirs
Copy link
Author

tukusejssirs commented May 11, 2022

As I could not find a way to define a variable with the contents of the remote file from /dev/fd/1, I created a function to get the file, save it temporarily, read the local file, remove the local file, and return the file contents.

It is not ideal (one could argue it could be done outside of samba-client), but I still this it should be part of the library.

/**
 * Read file contents of a remote file
 *
 * @param      {string}   file                   File name with path relative to remote share root folder
 * @param      {string}   encoding               Character encoding
 * @param      {string}   [tempPath='/dev/shm']  Temporary folder path
 * @param      {string}   workingDir             Working directory
 * @return     {Promise}  Remote file contents
 */
const {dirname, basename} = require('path')
const {access, constants, readFile, unlink} = require('fs-extra')

async readFileContents({file, encoding, tempPath = '/dev/shm', workingDir}) {
  const tempFileBase = `${tempPath}/${basename(file)}`
  let tempFile = tempFileBase
  let i = 0
  let created = false

  try {
    await access(tempPath, constants.R_OK | constants.W_OK)
  } catch (e) {
    throw e
  }

  while (!created) {
    try {
      await access(tempFile, constants.F_OK)
      i++
      tempFile = `${tempFileBase}_${i}`
    } catch {
      try {
        await this.getFile(file, tempFile, workingDir)
        created = true
      } catch {
        i++
        tempFile = `${tempFileBase}_${i}`
      }
    }
  }

  const content = (await readFile(tempFile, encoding)).toString()
  await unlink(tempFile)
  return content
}

Note that I could not make running smbclient via this library unless I changed getCleanedSmbClientArgs() function to not replace slashes to backslashes and use double quotes instead of single quotes. I have no idea if this breaks some other stuff within the library.

// const getCleanedSmbClientArgs = (args) => args.map((arg) => `'${arg.replace(/\//g, '\\')}'`).join(' ')
const getCleanedSmbClientArgs = (args) => args.map((arg) => `"${arg}"`).join(' ')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant