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; }
/** * 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; }
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; }
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; }
/* * 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; }