int win32_utime(const char *fname, struct utimbuf *times) { FILETIME acc; FILETIME mod; char tmpbuf[5000]; conv_unix_to_win32_path(fname, tmpbuf, 5000); cvt_utime_to_ftime(times->actime, acc); cvt_utime_to_ftime(times->modtime, mod); HANDLE h=INVALID_HANDLE_VALUE; if(p_CreateFileW) { char* pwszBuf=sm_get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf); h=p_CreateFileW((LPCWSTR)pwszBuf, FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE |FILE_SHARE_READ |FILE_SHARE_DELETE, NULL, OPEN_EXISTING, // required for directories FILE_FLAG_BACKUP_SEMANTICS, NULL); sm_free_pool_memory(pwszBuf); } else if(p_CreateFileA) { h=p_CreateFileA(tmpbuf, FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE |FILE_SHARE_READ |FILE_SHARE_DELETE, NULL, OPEN_EXISTING, // required for directories FILE_FLAG_BACKUP_SEMANTICS, NULL); } if(h==INVALID_HANDLE_VALUE) { const char *err=errorString(); fprintf(stderr, "Cannot open %s for utime(): ERR=%s\n", tmpbuf, err); LocalFree((void *)err); errno=b_errno_win32; return -1; } int rval=SetFileTime(h, NULL, &acc, &mod)?0:-1; CloseHandle(h); if(rval==-1) errno=b_errno_win32; return rval; }
static int win32_chmod_new(const char *path, int64_t winattr) { //if(winattr & FILE_ATTRIBUTE_ENCRYPTED) // printf("\n %s was encrypted!\n", path); DWORD attr=(DWORD)-1; if(p_GetFileAttributesW) { char *pwszBuf=sm_get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, path); attr=p_GetFileAttributesW((LPCWSTR) pwszBuf); if(attr!=INVALID_FILE_ATTRIBUTES) attr=p_SetFileAttributesW((LPCWSTR)pwszBuf, winattr & SET_ATTRS); sm_free_pool_memory(pwszBuf); } else if(p_GetFileAttributesA) { attr=p_GetFileAttributesA(path); if(attr!=INVALID_FILE_ATTRIBUTES) winattr=p_SetFileAttributesA(path, attr & SET_ATTRS); } if(attr==(DWORD)-1) { const char *err=errorString(); LocalFree((void *)err); errno=b_errno_win32; return -1; } return 0; }
int win32_chdir(const char *dir) { if(p_SetCurrentDirectoryW) { char *pwszBuf=sm_get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, dir); BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf); sm_free_pool_memory(pwszBuf); if(!b) { errno=b_errno_win32; return -1; } } else if(p_SetCurrentDirectoryA) { if(!p_SetCurrentDirectoryA(dir)) { errno=b_errno_win32; return -1; } } else return -1; return 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; }
static int win32_chmod_old(const char *path, mode_t mode) { DWORD attr=(DWORD)-1; if(p_GetFileAttributesW) { char *pwszBuf=sm_get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, path); attr=p_GetFileAttributesW((LPCWSTR)pwszBuf); if(attr!=INVALID_FILE_ATTRIBUTES) { // Use Burp mappings defined in stat() above. if(!(mode & (S_IRUSR|S_IRGRP|S_IROTH))) attr |= FILE_ATTRIBUTE_READONLY; else attr &= ~FILE_ATTRIBUTE_READONLY; if(!(mode & S_IRWXO)) attr |= FILE_ATTRIBUTE_SYSTEM; else attr &= ~FILE_ATTRIBUTE_SYSTEM; if(mode & S_ISVTX) attr |= FILE_ATTRIBUTE_HIDDEN; else attr &= ~FILE_ATTRIBUTE_HIDDEN; attr=p_SetFileAttributesW((LPCWSTR)pwszBuf, attr); } sm_free_pool_memory(pwszBuf); } else if (p_GetFileAttributesA) { if(!(mode & (S_IRUSR|S_IRGRP|S_IROTH))) attr |= FILE_ATTRIBUTE_READONLY; else attr &= ~FILE_ATTRIBUTE_READONLY; if(!(mode & S_IRWXO)) attr |= FILE_ATTRIBUTE_SYSTEM; else attr &= ~FILE_ATTRIBUTE_SYSTEM; if(mode & S_ISVTX) attr |= FILE_ATTRIBUTE_HIDDEN; else attr &= ~FILE_ATTRIBUTE_HIDDEN; attr=p_GetFileAttributesA(path); if(attr!=INVALID_FILE_ATTRIBUTES) attr=p_SetFileAttributesA(path, attr); } if(attr==(DWORD)-1) { const char *err=errorString(); LocalFree((void *)err); errno=b_errno_win32; return -1; } return 0; }
static int stat2(const char *file, struct stat *sb, uint64_t *winattr) { HANDLE h=INVALID_HANDLE_VALUE; int rval=0; char tmpbuf[5000]; conv_unix_to_win32_path(file, tmpbuf, 5000); DWORD attr=(DWORD)-1; if(p_GetFileAttributesW) { char* pwszBuf=sm_get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf); attr=p_GetFileAttributesW((LPCWSTR) pwszBuf); if(p_CreateFileW) h=CreateFileW((LPCWSTR)pwszBuf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); sm_free_pool_memory(pwszBuf); } else if(p_GetFileAttributesA) { attr=p_GetFileAttributesA(tmpbuf); h=CreateFileA(tmpbuf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); } if(attr==(DWORD)-1) { const char *err=errorString(); LocalFree((void *)err); if(h!=INVALID_HANDLE_VALUE) CloseHandle(h); errno=b_errno_win32; return -1; } if(h==INVALID_HANDLE_VALUE) { const char *err=errorString(); LocalFree((void *)err); errno=b_errno_win32; return -1; } rval=do_fstat((intptr_t)h, sb, winattr); CloseHandle(h); if(attr & FILE_ATTRIBUTE_DIRECTORY && file[1]==':' && file[2]) rval = statDir(file, sb, winattr); return rval; }
int win32_mkdir(const char *dir) { if(p_wmkdir) { char *pwszBuf=sm_get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, dir); int n=p_wmkdir((LPCWSTR)pwszBuf); sm_free_pool_memory(pwszBuf); return n; } return _mkdir(dir); }
char *make_win32_path_UTF8_2_wchar_w(const char *pszUTF) { int size=0; char *ret=NULL; char *tmp=sm_get_pool_memory(PM_FNAME); size=make_win32_path_UTF8_2_wchar(&tmp, pszUTF); if(size>0) { ret=(char *)malloc(2*strlen(pszUTF)+MAX_PATH); //ret=(char *)malloc((size+1)*sizeof(WCHAR)); wcscpy((LPWSTR)ret, (LPWSTR)tmp); } sm_free_pool_memory(tmp); return ret; }
/** * 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 int do_stat(const char *file, struct stat *sb, uint64_t *winattr) { WIN32_FILE_ATTRIBUTE_DATA data; errno=0; memset(sb, 0, sizeof(*sb)); memset(winattr, 0, sizeof(*winattr)); if(p_GetFileAttributesExW) { // Dynamically allocate enough space for UCS2 filename. char *pwszBuf=sm_get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, file); BOOL b=p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, &data); sm_free_pool_memory(pwszBuf); if(!b) return stat2(file, sb, winattr); } else if(p_GetFileAttributesExA) { if(!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) return stat2(file, sb, winattr); } else return stat2(file, sb, winattr); *winattr=(int64_t)data.dwFileAttributes; /* Graham says: all the following stuff seems rather complicated. It is probably not all needed anymore, since I have added *winattr above, which bacula did not do. One reason for keeping it is that some of the values get converted to unix-style permissions that show up in the long list functionality. I think I would prefer to remove it all though. */ sb->st_mode = 0777; // Start with everything. if(data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH); if(data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) sb->st_mode &= ~S_IRWXO; // Remove everything for other. if(data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) sb->st_mode |= S_ISVTX; // use sticky bit -> hidden. if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) sb->st_mode |= S_IFDIR; else sb->st_mode |= S_IFREG; // Use st_rdev to store reparse attribute. sb->st_rdev=(data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)?1:0; sb->st_nlink=1; sb->st_size=data.nFileSizeHigh; sb->st_size<<=32; sb->st_size|=data.nFileSizeLow; sb->st_blksize=4096; sb->st_blocks=(uint32_t)(sb->st_size + 4095)/4096; sb->st_atime=cvt_ftime_to_utime(data.ftLastAccessTime); sb->st_mtime=cvt_ftime_to_utime(data.ftLastWriteTime); sb->st_ctime=cvt_ftime_to_utime(data.ftCreationTime); /* If we are not at the root, then to distinguish a reparse point from a mount point, we must call FindFirstFile() to get the WIN32_FIND_DATA, which has the bit that indicates that this directory is a mount point -- aren't Win32 APIs wonderful? (sarcasm). The code exists in the statDir subroutine. */ if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && file[1]==':' && file[2]) statDir(file, sb, winattr); return 0; }
static int statDir(const char *file, struct stat *sb, uint64_t *winattr) { WIN32_FIND_DATAW info_w; // window's file info WIN32_FIND_DATAA info_a; // window's file info // cache some common vars to make code more transparent DWORD *pdwFileAttributes; DWORD *pnFileSizeHigh; DWORD *pnFileSizeLow; DWORD *pdwReserved0; FILETIME *pftLastAccessTime; FILETIME *pftLastWriteTime; FILETIME *pftCreationTime; /* Oh, cool, another exception: Microsoft doesn't let us do FindFile operations on a Drive, so simply fake root attibutes. */ if(file[1]==':' && !file[2]) { time_t now=time(NULL); sb->st_mode=S_IFDIR; sb->st_mode|=S_IREAD|S_IEXEC|S_IWRITE; sb->st_ctime=now; sb->st_mtime=now; sb->st_atime=now; sb->st_rdev=0; return 0; } HANDLE h=INVALID_HANDLE_VALUE; // use unicode if(p_FindFirstFileW) { char *pwszBuf=sm_get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, file); h=p_FindFirstFileW((LPCWSTR)pwszBuf, &info_w); sm_free_pool_memory(pwszBuf); pdwFileAttributes=&info_w.dwFileAttributes; pdwReserved0 =&info_w.dwReserved0; pnFileSizeHigh =&info_w.nFileSizeHigh; pnFileSizeLow =&info_w.nFileSizeLow; pftLastAccessTime=&info_w.ftLastAccessTime; pftLastWriteTime =&info_w.ftLastWriteTime; pftCreationTime =&info_w.ftCreationTime; // use ASCII } else if (p_FindFirstFileA) { h=p_FindFirstFileA(file, &info_a); pdwFileAttributes=&info_a.dwFileAttributes; pdwReserved0 =&info_a.dwReserved0; pnFileSizeHigh =&info_a.nFileSizeHigh; pnFileSizeLow =&info_a.nFileSizeLow; pftLastAccessTime=&info_a.ftLastAccessTime; pftLastWriteTime =&info_a.ftLastWriteTime; pftCreationTime =&info_a.ftCreationTime; } if(h==INVALID_HANDLE_VALUE) { const char *err = errorString(); /* Note, in creating leading paths, it is normal that the file does not exist. */ LocalFree((void *)err); errno=b_errno_win32; return -1; } else FindClose(h); *winattr=(int64_t)*pdwFileAttributes; /* Graham says: all the following stuff seems rather complicated. It is probably not all needed anymore, since I have added *winattr above, which bacula did not do. One reason for keeping it is that some of the values get converted to unix-style permissions that show up in the long list functionality. I think I would prefer to remove it all at some point. */ sb->st_mode = 0777; // start with everything if(*pdwFileAttributes & FILE_ATTRIBUTE_READONLY) sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH); if(*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM) sb->st_mode &= ~S_IRWXO; // remove everything for other if(*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN) sb->st_mode |= S_ISVTX; // use sticky bit -> hidden sb->st_mode |= S_IFDIR; /* Store reparse/mount point info in st_rdev. Note a Win32 reparse point (junction point) is like a link though it can have many properties (directory link, soft link, hard link, HSM, ... A mount point is a reparse point where another volume is mounted, so it is like a Unix mount point (change of filesystem). */ if(*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) sb->st_rdev=WIN32_MOUNT_POINT; else sb->st_rdev=0; if((*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (*pdwReserved0 & IO_REPARSE_TAG_MOUNT_POINT)) { sb->st_rdev=WIN32_MOUNT_POINT; /* Now to find out if the directory is a mount point or a reparse point, we must do a song and a dance. Explicitly open the file to read the reparse point, then call DeviceIoControl to find out if it points to a Volume or to a directory. */ h=INVALID_HANDLE_VALUE; if(p_GetFileAttributesW) { char *pwszBuf=sm_get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, file); if(p_CreateFileW) { h=CreateFileW((LPCWSTR)pwszBuf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); } sm_free_pool_memory(pwszBuf); } else if(p_GetFileAttributesA) { h=CreateFileA(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); } if(h!=INVALID_HANDLE_VALUE) { char dummy[1000]; REPARSE_DATA_BUFFER *rdb=(REPARSE_DATA_BUFFER *)dummy; rdb->ReparseTag=IO_REPARSE_TAG_MOUNT_POINT; DWORD bytes; bool ok; ok=DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, // in buffer, bytes (LPVOID)rdb, (DWORD)sizeof(dummy), // out buffer, btyes (LPDWORD)&bytes, (LPOVERLAPPED)0); if(ok) { char *utf8=sm_get_pool_memory(PM_NAME); wchar_2_UTF8(utf8, (wchar_t *) rdb->SymbolicLinkReparseBuffer.PathBuffer); if(!strncasecmp(utf8, "\\??\\volume{", 11)) sb->st_rdev=WIN32_MOUNT_POINT; else // Points to a directory so we ignore it. sb->st_rdev=WIN32_JUNCTION_POINT; sm_free_pool_memory(utf8); } CloseHandle(h); } } sb->st_size=*pnFileSizeHigh; sb->st_size<<=32; sb->st_size|=*pnFileSizeLow; sb->st_blksize=4096; sb->st_blocks=(uint32_t)(sb->st_size+4095)/4096; sb->st_atime=cvt_ftime_to_utime(*pftLastAccessTime); sb->st_mtime=cvt_ftime_to_utime(*pftLastWriteTime); sb->st_ctime=cvt_ftime_to_utime(*pftCreationTime); return 0; }
int win32_unlink(const char *filename) { int nRetCode; if(p_wunlink) { char* pwszBuf=sm_get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, filename); nRetCode=_wunlink((LPCWSTR) pwszBuf); /* Special case if file is readonly, we retry but unset attribute before. */ if(nRetCode==-1 && errno==EACCES && p_SetFileAttributesW && p_GetFileAttributesW) { DWORD dwAttr=p_GetFileAttributesW((LPCWSTR)pwszBuf); if(dwAttr!=INVALID_FILE_ATTRIBUTES) { if(p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) { nRetCode=_wunlink((LPCWSTR) pwszBuf); // Reset to original if it didn't help. if(nRetCode==-1) p_SetFileAttributesW( (LPCWSTR)pwszBuf, dwAttr); } } } sm_free_pool_memory(pwszBuf); } else { nRetCode=_unlink(filename); /* special case if file is readonly, we retry but unset attribute before. */ if(nRetCode==-1 && errno==EACCES && p_SetFileAttributesA && p_GetFileAttributesA) { DWORD dwAttr=p_GetFileAttributesA(filename); if(dwAttr!=INVALID_FILE_ATTRIBUTES) { if(p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) { nRetCode=_unlink(filename); // Reset to original if it didn't help. if(nRetCode==-1) p_SetFileAttributesA( filename, dwAttr); } } } } return nRetCode; }
DIR * opendir(const char *path) { ssize_t len=0; char *tspec=NULL; // Enough space for VSS! int max_len=strlen(path)+MAX_PATH; _dir *rval=NULL; if(!path) { errno=ENOENT; return NULL; } if(!(rval=(_dir *)malloc(sizeof(_dir)))) return NULL; memset(rval, 0, sizeof (_dir)); if(!(tspec=(char *)malloc(max_len))) { free(rval); return NULL; } conv_unix_to_win32_path(path, tspec, max_len); len=strlen(tspec); // Add backslash only if there is none yet (think of c:\). if(tspec[len-1] != '\\' && len+1<max_len) { tspec[len++]='\\'; tspec[len]='\0'; } if(len+1<max_len) { tspec[len++]='*'; tspec[len]='\0'; } rval->spec=tspec; // Convert to wchar_t. if(p_FindFirstFileW) { char *pwcBuf=sm_get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec); rval->dirh=p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w); sm_free_pool_memory(pwcBuf); if(rval->dirh!=INVALID_HANDLE_VALUE) rval->valid_w=1; } else if (p_FindFirstFileA) { rval->dirh=p_FindFirstFileA(rval->spec, &rval->data_a); if (rval->dirh!=INVALID_HANDLE_VALUE) rval->valid_a = 1; } else goto err; rval->offset=0; if(rval->dirh==INVALID_HANDLE_VALUE) goto err; if(rval->valid_w) { } if(rval->valid_a) { } return (DIR *)rval; err: free((void *)rval->spec); free(rval); errno=b_errno_win32; return NULL; }
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; }
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; }
/* * 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; }