Search code examples
c++permission-denied

"Permission denied" when opening file for writting second time


I am transferring a file from Linux to windows using library libssh in SFTP mode using C++ on Windows.

I am able to create a file on Windows side and write in it for once using this program:

int sftp_read_sync(ssh_session session, sftp_session sftp)
{
  int access_type;
  sftp_file file;
  char* buffer[MAX_XFER_BUF_SIZE];
  int nbytes, nwritten, rc;
  int fd;
  access_type = O_RDONLY;
  file = sftp_open(sftp, "/root/bel1.txt",
                   access_type, 0);
  if (file == NULL) {
      fprintf(stderr, "Can't open file for reading: %s\n",
              ssh_get_error(session));
      return SSH_ERROR;
  }
  fd = open("C:\\Users\\Wipro\\Desktop\\bel6.txt", O_WRONLY | O_CREAT  | O_TRUNC);
  if (fd < 0) {
      fprintf(stderr, "Can't open file for writing: %s\n",
              strerror(errno));
      return SSH_ERROR;
  }
  for (;;) {
      nbytes = sftp_read(file, buffer, sizeof(buffer));
      if (nbytes == 0) {
          break; // EOF
      } else if (nbytes < 0) {
          fprintf(stderr, "Error while reading file: %s\n",
                  ssh_get_error(session));
          sftp_close(file);
          return SSH_ERROR;
      }
      nwritten = write(fd, buffer, nbytes);
      if (nwritten != nbytes) {
          fprintf(stderr, "Error writing: %s\n",
                  strerror(errno));
          sftp_close(file);
          return SSH_ERROR;
      }
  }
  rc = sftp_close(file);
  if (rc != SSH_OK) {
      fprintf(stderr, "Can't close the read file: %s\n",
              ssh_get_error(session));
      return rc;
  }
  return SSH_OK;
}

On running this same program again, I'm getting an error:

Can't open file for writing: Permission denied

The file created is not having a permission to rewrite in it.

How can I correct this?


Solution

  • On Windows, open() is deprecated and you should use _open() or, even preferred, _sopen_s() instead.

    _open() has an optional parameter "int pmode" which allows you to set file permissions:

    int _open(
       const char *filename,
       int oflag [,
       int pmode] 
    );
    

    For pmode, you can specify

    _S_IREAD
      Only reading permitted.
    _S_IWRITE
      Writing permitted. (In effect, permits reading and writing.)
    _S_IREAD | _S_IWRITE
      Reading and writing permitted.
    

    So just replace your statement

    fd = open("C:\\Users\\Wipro\\Desktop\\bel6.txt", O_WRONLY | O_CREAT  | O_TRUNC);
    

    with

    fd = _open("C:\\Users\\Wipro\\Desktop\\bel6.txt", O_WRONLY | O_CREAT  | O_TRUNC, _S_IREAD | _S_IWRITE);
    

    and you should be fine. See https://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx for further details.

    Since you are on Windows, you can also use _sopen_s() instead of open(). _sopen_s() also allows to specify file permissions. Its API is different and looks like

    errno_t _sopen_s(
       int* pfh,
       const char *filename,
       int oflag,
       int shflag,
       int pmode
    );
    

    According to https://msdn.microsoft.com/en-us/library/w64k0ytk.aspx, the parameters are

    [out] pfh
      The file handle, or -1 in the case of an error.
    [in] filename
      File name.
    [in] oflag
      The kind of operations allowed.
    [in] shflag
      The kind of sharing allowed.
    [in] pmode
      Permission setting.
    

    So you can replace your statement

    fd = open("C:\\Users\\Wipro\\Desktop\\bel6.txt", O_WRONLY | O_CREAT  | O_TRUNC);
    

    with

    int fd;
    int err = _sopen_s( &fd, "C:\\Users\\Wipro\\Desktop\\bel6.txt", O_WRONLY | O_CREAT | O_TRUNC, _SH_DENYNO, _S_IREAD | _S_IWRITE );
    if (err) {
        fprintf( stderr, "Can't open file for writing: %s\n",
          strerror( errno ) );
        return errno;
      }
    

    Other possible values for the paramerers are documented meticulously at https://msdn.microsoft.com/en-us/library/w64k0ytk.aspx .

    At the end, no matter whether you use _open() or _sopen_s(), you should still close your file (it is then, when the file permissions are set):

    _close( fh );
    

    Finally, you will need the following headers:

    #include <io.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <iostream>
    #include <sys/stat.h>
    #include <errno.h>