Esempio n. 1
0
int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
{
   char *p = attribsEx;
   WIN32_FILE_ATTRIBUTE_DATA atts;
   ULARGE_INTEGER li;

   attribsEx[0] = 0;                  /* no extended attributes */

   if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) {
      return STREAM_UNIX_ATTRIBUTES;
   }

   unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname);

   /** try unicode version */
   if (p_GetFileAttributesExW)  {
      POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);   
      make_win32_path_UTF8_2_wchar(&pwszBuf, ff_pkt->fname);

      BOOL b=p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, 
                                    (LPVOID)&atts);
      free_pool_memory(pwszBuf);

      if (!b) {
         win_error(jcr, "GetFileAttributesExW:", ff_pkt->sys_fname);
         return STREAM_UNIX_ATTRIBUTES;
      }
   }
   else {
      if (!p_GetFileAttributesExA)
         return STREAM_UNIX_ATTRIBUTES;      

      if (!p_GetFileAttributesExA(ff_pkt->sys_fname, GetFileExInfoStandard,
                              (LPVOID)&atts)) {
         win_error(jcr, "GetFileAttributesExA:", ff_pkt->sys_fname);
         return STREAM_UNIX_ATTRIBUTES;
      }
   }

   p += to_base64((uint64_t)atts.dwFileAttributes, p);
   *p++ = ' ';                        /* separate fields with a space */
   li.LowPart = atts.ftCreationTime.dwLowDateTime;
   li.HighPart = atts.ftCreationTime.dwHighDateTime;
   p += to_base64((uint64_t)li.QuadPart, p);
   *p++ = ' ';
   li.LowPart = atts.ftLastAccessTime.dwLowDateTime;
   li.HighPart = atts.ftLastAccessTime.dwHighDateTime;
   p += to_base64((uint64_t)li.QuadPart, p);
   *p++ = ' ';
   li.LowPart = atts.ftLastWriteTime.dwLowDateTime;
   li.HighPart = atts.ftLastWriteTime.dwHighDateTime;
   p += to_base64((uint64_t)li.QuadPart, p);
   *p++ = ' ';
   p += to_base64((uint64_t)atts.nFileSizeHigh, p);
   *p++ = ' ';
   p += to_base64((uint64_t)atts.nFileSizeLow, p);
   *p = 0;
   return STREAM_UNIX_ATTRIBUTES_EX;
}
Esempio n. 2
0
/**
 * Set Extended File Attributes for Win32
 *
 *  fname is the original filename
 *  ofile is the output filename (may be in a different directory)
 *
 * Returns:  true  on success
 *           false on failure
 */
static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
{
   char *p = attr->attrEx;
   int64_t val;
   WIN32_FILE_ATTRIBUTE_DATA atts;
   ULARGE_INTEGER li;
   POOLMEM *win32_ofile;

   /** if we have neither Win ansi nor wchar API, get out */
   if (!(p_SetFileAttributesW || p_SetFileAttributesA)) {
      return false;
   }

   if (!p || !*p) {                   /* we should have attributes */
      Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", attr->ofname, ofd->fid);
      if (is_bopen(ofd)) {
         bclose(ofd);
      }
      return false;
   } else {
      Dmsg2(100, "Attribs %s = %s\n", attr->ofname, attr->attrEx);
   }

   p += from_base64(&val, p);
   plug(atts.dwFileAttributes, val);
   p++;                               /* skip space */
   p += from_base64(&val, p);
   li.QuadPart = val;
   atts.ftCreationTime.dwLowDateTime = li.LowPart;
   atts.ftCreationTime.dwHighDateTime = li.HighPart;
   p++;                               /* skip space */
   p += from_base64(&val, p);
   li.QuadPart = val;
   atts.ftLastAccessTime.dwLowDateTime = li.LowPart;
   atts.ftLastAccessTime.dwHighDateTime = li.HighPart;
   p++;                               /* skip space */
   p += from_base64(&val, p);
   li.QuadPart = val;
   atts.ftLastWriteTime.dwLowDateTime = li.LowPart;
   atts.ftLastWriteTime.dwHighDateTime = li.HighPart;
   p++;
   p += from_base64(&val, p);
   plug(atts.nFileSizeHigh, val);
   p++;
   p += from_base64(&val, p);
   plug(atts.nFileSizeLow, val);

   /** Convert to Windows path format */
   win32_ofile = get_pool_memory(PM_FNAME);
   unix_name_to_win32(&win32_ofile, attr->ofname);

   /** At this point, we have reconstructed the WIN32_FILE_ATTRIBUTE_DATA pkt */

   if (!is_bopen(ofd)) {
      Dmsg1(100, "File not open: %s\n", attr->ofname);
      bopen(ofd, attr->ofname, O_WRONLY|O_BINARY, 0);   /* attempt to open the file */
   }

   if (is_bopen(ofd)) {
      Dmsg1(100, "SetFileTime %s\n", attr->ofname);
      if (!SetFileTime(bget_handle(ofd),
                         &atts.ftCreationTime,
                         &atts.ftLastAccessTime,
                         &atts.ftLastWriteTime)) {
         win_error(jcr, "SetFileTime:", win32_ofile);
      }
      bclose(ofd);
   }

   Dmsg1(100, "SetFileAtts %s\n", attr->ofname);
   if (!(atts.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
      if (p_SetFileAttributesW) {
         POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);   
         make_win32_path_UTF8_2_wchar(&pwszBuf, attr->ofname);

         BOOL b=p_SetFileAttributesW((LPCWSTR)pwszBuf, atts.dwFileAttributes & SET_ATTRS);
         free_pool_memory(pwszBuf);
      
         if (!b) 
            win_error(jcr, "SetFileAttributesW:", win32_ofile); 
      }
      else {
         if (!p_SetFileAttributesA(win32_ofile, atts.dwFileAttributes & SET_ATTRS)) {
            win_error(jcr, "SetFileAttributesA:", win32_ofile);
         }
      }
   }
   free_pool_memory(win32_ofile);
   return true;
}
Esempio n. 3
0
File: bfile.c Progetto: AlD/bareos
static inline int bopen_encrypted(BFILE *bfd, const char *fname, int flags, mode_t mode)
{
   bool is_dir;
   ULONG ulFlags = 0;
   POOLMEM *win32_fname;
   POOLMEM *win32_fname_wchar;

   if (!p_OpenEncryptedFileRawA && !p_OpenEncryptedFileRawW) {
      Dmsg0(50, "No p_OpenEncryptedFileRawA and no p_OpenEncryptedFileRawW!!!!!\n");
      return 0;
   }

   is_dir = S_ISDIR(mode);

   /*
    * Convert to Windows path format
    */
   win32_fname = get_pool_memory(PM_FNAME);
   win32_fname_wchar = get_pool_memory(PM_FNAME);

   unix_name_to_win32(&win32_fname, (char *)fname);

   if (p_OpenEncryptedFileRawW && p_MultiByteToWideChar) {
      make_win32_path_UTF8_2_wchar(&win32_fname_wchar, fname);
   }

   /*
    * See if we open the file for create or read-write.
    */
   if ((flags & O_CREAT) || (flags & O_WRONLY)) {
      if (is_dir) {
         ulFlags |= CREATE_FOR_IMPORT | OVERWRITE_HIDDEN | CREATE_FOR_DIR;
      } else {
         ulFlags |= CREATE_FOR_IMPORT | OVERWRITE_HIDDEN;
      }
      bfd->mode = BF_WRITE;
   } else {
      ulFlags = CREATE_FOR_EXPORT;
      bfd->mode = BF_READ;
   }

   if (p_OpenEncryptedFileRawW && p_MultiByteToWideChar) {
      /*
       * Unicode open.
       */
      Dmsg1(100, "OpenEncryptedFileRawW=%s\n", win32_fname);
      if (p_OpenEncryptedFileRawW((LPCWSTR)win32_fname_wchar,
                                  ulFlags,
                                  &(bfd->pvContext))) {
         bfd->mode = BF_CLOSED;
      }
   } else {
      /*
       * ASCII open.
       */
      Dmsg1(100, "OpenEncryptedFileRawA=%s\n", win32_fname);
      if (p_OpenEncryptedFileRawA(win32_fname_wchar,
                                  ulFlags,
                                  &(bfd->pvContext))) {
         bfd->mode=BF_CLOSED;
      }
   }

   free_pool_memory(win32_fname_wchar);
   free_pool_memory(win32_fname);

   bfd->encrypted = true;

   return bfd->mode == BF_CLOSED ? -1 : 1;
}
Esempio n. 4
0
File: bfile.c Progetto: AlD/bareos
static inline int bopen_nonencrypted(BFILE *bfd, const char *fname, int flags, mode_t mode)
{
   POOLMEM *win32_fname;
   POOLMEM *win32_fname_wchar;
   DWORD dwaccess, dwflags, dwshare;

   /*
    * Convert to Windows path format
    */
   win32_fname = get_pool_memory(PM_FNAME);
   win32_fname_wchar = get_pool_memory(PM_FNAME);

   unix_name_to_win32(&win32_fname, (char *)fname);

   if (bfd->cmd_plugin && plugin_bopen) {
      int rtnstat;
      Dmsg1(50, "call plugin_bopen fname=%s\n", fname);
      rtnstat = plugin_bopen(bfd, fname, flags, mode);
      Dmsg1(50, "return from plugin_bopen status=%d\n", rtnstat);
      if (rtnstat >= 0) {
         if (flags & O_CREAT || flags & O_WRONLY) {   /* Open existing for write */
            Dmsg1(50, "plugin_open for write OK file=%s.\n", fname);
            bfd->mode = BF_WRITE;
         } else {
            Dmsg1(50, "plugin_open for read OK file=%s.\n", fname);
            bfd->mode = BF_READ;
         }
      } else {
         bfd->mode = BF_CLOSED;
         Dmsg1(000, "==== plugin_bopen returned bad status=%d\n", rtnstat);
      }
      free_pool_memory(win32_fname_wchar);
      free_pool_memory(win32_fname);
      return bfd->mode == BF_CLOSED ? -1 : 1;
   }
   Dmsg0(50, "=== NO plugin\n");

   if (!(p_CreateFileA || p_CreateFileW)) {
      Dmsg0(50, "No CreateFileA and no CreateFileW!!!!!\n");
      return 0;
   }

   if (p_CreateFileW && p_MultiByteToWideChar) {
      make_win32_path_UTF8_2_wchar(&win32_fname_wchar, fname);
   }

   if (flags & O_CREAT) {             /* Create */
      if (bfd->use_backup_api) {
         dwaccess = GENERIC_WRITE | FILE_ALL_ACCESS | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY;
         dwflags = FILE_FLAG_BACKUP_SEMANTICS;
      } else {
         dwaccess = GENERIC_WRITE;
         dwflags = 0;
      }

      /*
       * Unicode open for create write
       */
      if (p_CreateFileW && p_MultiByteToWideChar) {
         Dmsg1(100, "Create CreateFileW=%s\n", win32_fname);
         bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
                                  dwaccess,      /* Requested access */
                                  0,             /* Shared mode */
                                  NULL,          /* SecurityAttributes */
                                  CREATE_ALWAYS, /* CreationDisposition */
                                  dwflags,       /* Flags and attributes */
                                  NULL);         /* TemplateFile */
      } else {
         /*
          * ASCII open
          */
         Dmsg1(100, "Create CreateFileA=%s\n", win32_fname);
         bfd->fh = p_CreateFileA(win32_fname,
                                 dwaccess,      /* Requested access */
                                 0,             /* Shared mode */
                                 NULL,          /* SecurityAttributes */
                                 CREATE_ALWAYS, /* CreationDisposition */
                                 dwflags,       /* Flags and attributes */
                                 NULL);         /* TemplateFile */
      }

      bfd->mode = BF_WRITE;
   } else if (flags & O_WRONLY) {
      /*
       * Open existing for write
       */
      if (bfd->use_backup_api) {
         dwaccess = GENERIC_WRITE | WRITE_OWNER | WRITE_DAC;
         if (flags & O_NOFOLLOW) {
            dwflags = FILE_FLAG_BACKUP_SEMANTICS;
         } else {
            dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
         }
      } else {
         dwaccess = GENERIC_WRITE;
         dwflags = 0;
      }

      if (p_CreateFileW && p_MultiByteToWideChar) {
         /*
          * unicode open for open existing write
          */
         Dmsg1(100, "Write only CreateFileW=%s\n", win32_fname);
         bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
                                 dwaccess,      /* Requested access */
                                 0,             /* Shared mode */
                                 NULL,          /* SecurityAttributes */
                                 OPEN_EXISTING, /* CreationDisposition */
                                 dwflags,       /* Flags and attributes */
                                 NULL);         /* TemplateFile */
      } else {
         /*
          * ASCII open
          */
         Dmsg1(100, "Write only CreateFileA=%s\n", win32_fname);
         bfd->fh = p_CreateFileA(win32_fname,
                                 dwaccess,      /* Requested access */
                                 0,             /* Shared mode */
                                 NULL,          /* SecurityAttributes */
                                 OPEN_EXISTING, /* CreationDisposition */
                                 dwflags,       /* Flags and attributes */
                                 NULL);         /* TemplateFile */

      }

      bfd->mode = BF_WRITE;
   } else {
      /*
       * Open existing for read
       */
      if (bfd->use_backup_api) {
         dwaccess = GENERIC_READ | READ_CONTROL | ACCESS_SYSTEM_SECURITY;
         if (flags & O_NOFOLLOW) {
            dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN;
         } else {
            dwflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OPEN_REPARSE_POINT;
         }
         dwshare = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
      } else {
         dwaccess = GENERIC_READ;
         dwflags = 0;
         dwshare = FILE_SHARE_READ | FILE_SHARE_WRITE;
      }

      if (p_CreateFileW && p_MultiByteToWideChar) {
         /*
          * Unicode open for open existing read
          */
         Dmsg1(100, "Read CreateFileW=%s\n", win32_fname);
         bfd->fh = p_CreateFileW((LPCWSTR)win32_fname_wchar,
                                 dwaccess,      /* Requested access */
                                 dwshare,       /* Share modes */
                                 NULL,          /* SecurityAttributes */
                                 OPEN_EXISTING, /* CreationDisposition */
                                 dwflags,       /* Flags and attributes */
                                 NULL);         /* TemplateFile */
      } else {
         /*
          * ASCII open for open existing read
          */
         Dmsg1(100, "Read CreateFileA=%s\n", win32_fname);
         bfd->fh = p_CreateFileA(win32_fname,
                                 dwaccess,      /* Requested access */
                                 dwshare,       /* Share modes */
                                 NULL,          /* SecurityAttributes */
                                 OPEN_EXISTING, /* CreationDisposition */
                                 dwflags,       /* Flags and attributes */
                                 NULL);         /* TemplateFile */
      }

      bfd->mode = BF_READ;
   }

   if (bfd->fh == INVALID_HANDLE_VALUE) {
      bfd->lerror = GetLastError();
      bfd->berrno = b_errno_win32;
      errno = b_errno_win32;
      bfd->mode = BF_CLOSED;
   }

   bfd->errmsg = NULL;
   bfd->lpContext = NULL;
   bfd->win32DecompContext.bIsInData = false;
   bfd->win32DecompContext.liNextHeader = 0;
   free_pool_memory(win32_fname_wchar);
   free_pool_memory(win32_fname);

   bfd->encrypted = false;

   return bfd->mode == BF_CLOSED ? -1 : 1;
}
Esempio n. 5
0
/*
 * Restore all file attributes like owner, mode and file times.
 */
static inline bool restore_file_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
{
    bool ok = true;
    bool suppress_errors;
#if defined(HAVE_FCHOWN) || defined(HAVE_FCHMOD) || defined(HAVE_FUTIMES) || defined(FUTIMENS)
    bool file_is_open;

    /*
     * Save if we are working on an open file.
     */
    file_is_open = is_bopen(ofd);
#endif

    /*
     * See if we want to print errors.
     */
    suppress_errors = (debug_level >= 100 || my_uid != 0);

    /*
     * Restore owner and group.
     */
#ifdef HAVE_FCHOWN
    if (file_is_open) {
        if (fchown(ofd->fid, attr->statp.st_uid, attr->statp.st_gid) < 0 && !suppress_errors) {
            berrno be;

            Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"), attr->ofname, be.bstrerror());
            ok = false;
        }
    } else {
#else
    {
#endif
        if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && !suppress_errors) {
            berrno be;

            Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"), attr->ofname, be.bstrerror());
            ok = false;
        }
    }

    /*
     * Restore filemode.
     */
#ifdef HAVE_FCHMOD
    if (file_is_open) {
        if (fchmod(ofd->fid, attr->statp.st_mode) < 0 && !suppress_errors) {
            berrno be;

            Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"), attr->ofname, be.bstrerror());
            ok = false;
        }
    } else {
#else
    {
#endif
#if defined(HAVE_WIN32)
        if (win32_chmod(attr->ofname, attr->statp.st_mode, attr->statp.st_rdev) < 0 && !suppress_errors) {
#else
        if (lchmod(attr->ofname, attr->statp.st_mode) < 0 && !suppress_errors) {
#endif
            berrno be;

            Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"), attr->ofname, be.bstrerror());
            ok = false;
        }
    }

    /*
     * Reset file times.
     */
#if defined(HAVE_FUTIMES)
    if (file_is_open) {
        struct timeval restore_times[2];

        restore_times[0].tv_sec = attr->statp.st_atime;
        restore_times[0].tv_usec = 0;
        restore_times[1].tv_sec = attr->statp.st_mtime;
        restore_times[1].tv_usec = 0;

        if (futimes(ofd->fid, restore_times) < 0 && !suppress_errors) {
            berrno be;

            Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"), attr->ofname, be.bstrerror());
            ok = false;
        }
    } else {
#elif defined(HAVE_FUTIMENS)
    if (file_is_open) {
        struct timespec restore_times[2];

        restore_times[0].tv_sec = attr->statp.st_atime;
        restore_times[0].tv_nsec = 0;
        restore_times[1].tv_sec = attr->statp.st_mtime;
        restore_times[1].tv_nsec = 0;

        if (futimens(ofd->fid, restore_times) < 0 && !suppress_errors) {
            berrno be;

            Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"), attr->ofname, be.bstrerror());
            ok = false;
        }
    } else {
#else
    {
#endif
#if defined(HAVE_LUTIMES)
        struct timeval restore_times[2];

        restore_times[0].tv_sec = attr->statp.st_atime;
        restore_times[0].tv_usec = 0;
        restore_times[1].tv_sec = attr->statp.st_mtime;
        restore_times[1].tv_usec = 0;

        if (lutimes(attr->ofname, restore_times) < 0 && !suppress_errors) {
            berrno be;

            Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"), attr->ofname, be.bstrerror());
            ok = false;
        }
#elif defined(HAVE_UTIMES)
        struct timeval restore_times[2];

        restore_times[0].tv_sec = attr->statp.st_atime;
        restore_times[0].tv_usec = 0;
        restore_times[1].tv_sec = attr->statp.st_mtime;
        restore_times[1].tv_usec = 0;

        if (utimes(attr->ofname, restore_times) < 0 && !suppress_errors) {
            berrno be;

            Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"), attr->ofname, be.bstrerror());
            ok = false;
        }
#else
        struct utimbuf restore_times;

        restore_times.actime = attr->statp.st_atime;
        restore_times.modtime = attr->statp.st_mtime;

        if (utime(attr->ofname, &restore_times) < 0 && !suppress_errors) {
            berrno be;

            Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"), attr->ofname, be.bstrerror());
            ok = false;
        }
#endif /* HAVE_LUTIMES */
    }

    return ok;
}

/**
 * Set file modes, permissions and times
 *
 *  fname is the original filename
 *  ofile is the output filename (may be in a different directory)
 *
 * Returns:  true  on success
 *           false on failure
 */
bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
{
    mode_t old_mask;
    bool ok = true;
    bool suppress_errors;

    if (uid_set) {
        my_uid = getuid();
        my_gid = getgid();
        uid_set = true;
    }

    /*
     * See if we want to print errors.
     */
    suppress_errors = (debug_level >= 100 || my_uid != 0);

#if defined(HAVE_WIN32)
    if (attr->stream == STREAM_UNIX_ATTRIBUTES_EX &&
            set_win32_attributes(jcr, attr, ofd)) {
        if (is_bopen(ofd)) {
            bclose(ofd);
        }
        pm_strcpy(attr->ofname, "*None*");
        return true;
    }

    if (attr->data_stream == STREAM_WIN32_DATA ||
            attr->data_stream == STREAM_WIN32_GZIP_DATA ||
            attr->data_stream == STREAM_WIN32_COMPRESSED_DATA) {
        if (is_bopen(ofd)) {
            bclose(ofd);
        }
        pm_strcpy(attr->ofname, "*None*");
        return true;
    }

    /**
     * If Windows stuff failed, e.g. attempt to restore Unix file to Windows, simply fall
     * through and we will do it the universal way.
     */
#endif

    old_mask = umask(0);
    if (is_bopen(ofd)) {
        boffset_t fsize;
        char ec1[50], ec2[50];

        fsize = blseek(ofd, 0, SEEK_END);
        if (attr->type == FT_REG &&
                fsize > 0 &&
                attr->statp.st_size > 0 &&
                fsize != (boffset_t)attr->statp.st_size) {
            Jmsg3(jcr, M_ERROR, 0, _("File size of restored file %s not correct. Original %s, restored %s.\n"),
                  attr->ofname, edit_uint64(attr->statp.st_size, ec1), edit_uint64(fsize, ec2));
        }
    } else {
        struct stat st;
        char ec1[50], ec2[50];

        if (lstat(attr->ofname, &st) == 0) {
            if (attr->type == FT_REG &&
                    st.st_size > 0 &&
                    attr->statp.st_size > 0 &&
                    st.st_size != attr->statp.st_size) {
                Jmsg3(jcr, M_ERROR, 0, _("File size of restored file %s not correct. Original %s, restored %s.\n"),
                      attr->ofname, edit_uint64(attr->statp.st_size, ec1), edit_uint64(st.st_size, ec2));
            }
        }
    }

    /**
     * We do not restore sockets, so skip trying to restore their attributes.
     */
    if (attr->type == FT_SPEC && S_ISSOCK(attr->statp.st_mode)) {
        goto bail_out;
    }

    /* ***FIXME**** optimize -- don't do if already correct */
    /**
     * For link, change owner of link using lchown, but don't try to do a chmod as that will update the file behind it.
     */
    if (attr->type == FT_LNK) {
        /*
         * Change owner of link, not of real file
         */
        if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && !suppress_errors) {
            berrno be;

            Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"), attr->ofname, be.bstrerror());
            ok = false;
        }

#ifdef HAVE_LCHMOD
        if (lchmod(attr->ofname, attr->statp.st_mode) < 0 && !suppress_errors) {
            berrno be;

            Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"), attr->ofname, be.bstrerror());
            ok = false;
        }
#endif
    } else {
        if (!ofd->cmd_plugin) {
            ok = restore_file_attributes(jcr, attr, ofd);

#ifdef HAVE_CHFLAGS
            /**
             * FreeBSD user flags
             *
             * Note, this should really be done before the utime() above,
             * but if the immutable bit is set, it will make the utimes()
             * fail.
             */
            if (chflags(attr->ofname, attr->statp.st_flags) < 0 && !suppress_errors) {
                berrno be;
                Jmsg2(jcr, M_ERROR, 0, _("Unable to set file flags %s: ERR=%s\n"), attr->ofname, be.bstrerror());
                ok = false;
            }
#endif
        }
    }

bail_out:
    if (is_bopen(ofd)) {
        bclose(ofd);
    }

    pm_strcpy(attr->ofname, "*None*");
    umask(old_mask);

    return ok;
}

#if !defined(HAVE_WIN32)
/*=============================================================*/
/*                                                             */
/*                 * * *  U n i x * * * *                      */
/*                                                             */
/*=============================================================*/

/**
 * It is possible to piggyback additional data e.g. ACLs on
 *   the encode_stat() data by returning the extended attributes
 *   here.  They must be "self-contained" (i.e. you keep track
 *   of your own length), and they must be in ASCII string
 *   format. Using this feature is not recommended.
 * The code below shows how to return nothing.  See the Win32
 *   code below for returning something in the attributes.
 */
int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
{
#ifdef HAVE_DARWIN_OS
    /**
     * We save the Mac resource fork length so that on a
     * restore, we can be sure we put back the whole resource.
     */
    char *p;

    *attribsEx = 0;                 /* no extended attributes (yet) */
    if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) {
        return STREAM_UNIX_ATTRIBUTES;
    }
    p = attribsEx;
    if (bit_is_set(FO_HFSPLUS, ff_pkt->flags)) {
        p += to_base64((uint64_t)(ff_pkt->hfsinfo.rsrclength), p);
    }
    *p = 0;
#else
    *attribsEx = 0;                    /* no extended attributes */
#endif
    return STREAM_UNIX_ATTRIBUTES;
}
#else
/*=============================================================*/
/*                                                             */
/*                 * * *  W i n 3 2 * * * *                    */
/*                                                             */
/*=============================================================*/
int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
{
    char *p = attribsEx;
    WIN32_FILE_ATTRIBUTE_DATA atts;
    ULARGE_INTEGER li;

    attribsEx[0] = 0;                  /* no extended attributes */

    if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) {
        return STREAM_UNIX_ATTRIBUTES;
    }

    unix_name_to_win32(ff_pkt->sys_fname, ff_pkt->fname);
    if (p_GetFileAttributesExW)  {
        /**
         * Try unicode version
         */
        POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
        make_win32_path_UTF8_2_wchar(pwszBuf, ff_pkt->fname);

        BOOL b=p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard,
                                      (LPVOID)&atts);
        free_pool_memory(pwszBuf);

        if (!b) {
            win_error(jcr, "GetFileAttributesExW:", ff_pkt->sys_fname);
            return STREAM_UNIX_ATTRIBUTES;
        }
    } else {
        if (!p_GetFileAttributesExA)
            return STREAM_UNIX_ATTRIBUTES;

        if (!p_GetFileAttributesExA(ff_pkt->sys_fname, GetFileExInfoStandard,
                                    (LPVOID)&atts)) {
            win_error(jcr, "GetFileAttributesExA:", ff_pkt->sys_fname);
            return STREAM_UNIX_ATTRIBUTES;
        }
    }

    /*
     * Instead of using the current dwFileAttributes use the
     * ff_pkt->statp.st_rdev which contains the actual fileattributes we
     * want to save for this file.
     */
    atts.dwFileAttributes = ff_pkt->statp.st_rdev;

    p += to_base64((uint64_t)atts.dwFileAttributes, p);
    *p++ = ' ';                        /* separate fields with a space */
    li.LowPart = atts.ftCreationTime.dwLowDateTime;
    li.HighPart = atts.ftCreationTime.dwHighDateTime;
    p += to_base64((uint64_t)li.QuadPart, p);
    *p++ = ' ';
    li.LowPart = atts.ftLastAccessTime.dwLowDateTime;
    li.HighPart = atts.ftLastAccessTime.dwHighDateTime;
    p += to_base64((uint64_t)li.QuadPart, p);
    *p++ = ' ';
    li.LowPart = atts.ftLastWriteTime.dwLowDateTime;
    li.HighPart = atts.ftLastWriteTime.dwHighDateTime;
    p += to_base64((uint64_t)li.QuadPart, p);
    *p++ = ' ';
    p += to_base64((uint64_t)atts.nFileSizeHigh, p);
    *p++ = ' ';
    p += to_base64((uint64_t)atts.nFileSizeLow, p);
    *p = 0;

    return STREAM_UNIX_ATTRIBUTES_EX;
}