/* (C) 2003-2007 Willem Jan Hengeveld * Web: http://www.xs4all.nl/~itsme/ * http://wiki.xda-developers.com/ * * $Id: pput.cpp 1908 2008-07-30 14:06:04Z itsme $ */ // todo: * support unicode filenames // -> need to create win32 file function lib which supports both 'A' and 'W' calls, to be able to stay backwd compatible with w9x // * support %CE1% etc path indicators // .... names are somewhere in shellres.dll // PARTIALLY DONE: now have csidl paths // // "pput -c filename" should return an error when the file exists. // // pget \path\wild* should return an error when the file exists, // ( and fails to copy because it does not overwrite ) // /* csidl values http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/enums/csidl.asp %ce% values: http://msdn.microsoft.com/library/en-us/dv_evtuv/html/etgrfwindowscedirectoryidentifiers.asp CEShell_77 : get %CE% path CEShell_76 : get csidl path see also SHGetSpecialFolderLocation, SHGetSpecialFolderPath CeGetSpecialFolderPath %CE% csidl path shellres string 00 12 "\" 0x2267 06 "\Program Files\Accessories" 0x2281 07 "\Program Files\Communication" 0x2282 08 "\Program Files\Games" 0x2283 0a "\Program Files\Office" 0x2285 09 "\Program Files\Pocket Outlook" 0x2284 10 "\Windows\Recent" 0x2262 11 "\Windows\Start Menu" 0x2266 0b "\Windows\Start Menu" 0x228a 0c "\Windows\Start Menu\Accessories" 0x2286 0d "\Windows\Start Menu\Communication" 0x2287 0e "\Windows\Start Menu\Games" 0x2288 00 {00021400-0000-0000-C000-000000000046} CSIDL_DESKTOP 03 00 "\My Documents" 0x2260 01 CSIDL_INTERNET // Internet Explorer (icon on desktop) 0b 02 "\Windows\Start Menu\Programs" 0x2263 CSIDL_PROGRAMS 03 {000314fe-0000-0000-C000-000000000046} CSIDL_CONTROLS - control panel 04 CSIDL_PRINTERS - My Computer\Printers 05 05 "\My Documents" 0x2269 CSIDL_PERSONAL 06 "\Windows\Favorites" 0x2264 CSIDL_FAVORITES 04 07 "\Windows\StartUp" 0x2261 CSIDL_STARTUP 08 CSIDL_RECENT 09 CSIDL_SENDTO 0a {000214A1-0000-0000-C000-000000000046} CSIDL_BITBUCKET - Recycle Bin 0b "\My Documents\My Music" 0x2274 0b CSIDL_STARTMENU // \Start Menu 0c CSIDL_MYDOCUMENTS // logical "My Documents" desktop icon 0d CSIDL_MYMUSIC // "My Music" folder 0e CSIDL_MYVIDEO // "My Videos" folder 0f 10 CSIDL_DESKTOPDIRECTORY // \Desktop 11 {000214A0-0000-0000-C000-000000000046} CSIDL_DRIVES // My Computer 12 CSIDL_NETWORK // Network Neighborhood (My Network Places) 13 CSIDL_NETHOOD // \nethood 0f 14 "\Windows\Fonts" 0x2265 CSIDL_FONTS 15 CSIDL_TEMPLATES 16 CSIDL_COMMON_STARTMENU // All Users\Start Menu 17 CSIDL_COMMON_PROGRAMS // All Users\Start Menu\Programs 18 CSIDL_COMMON_STARTUP // All Users\Startup 19 CSIDL_COMMON_DESKTOPDIRECTORY // All Users\Desktop 13 1a "\Application Data" 0x2268 CSIDL_APPDATA 1b CSIDL_PRINTHOOD // \PrintHood 1c CSIDL_LOCAL_APPDATA // non roaming, user\Local Settings\Application Data 1d CSIDL_ALTSTARTUP // non localized startup 1e CSIDL_COMMON_ALTSTARTUP // non localized common startup 1f CSIDL_COMMON_FAVORITES 20 CSIDL_INTERNET_CACHE 21 CSIDL_COOKIES 22 CSIDL_HISTORY 23 CSIDL_COMMON_APPDATA // All Users\Application Data 02 24 "\Windows" 0x2280 CSIDL_WINDOWS 25 CSIDL_SYSTEM // GetSystemDirectory() 01 26 "\Program Files" 0x2289 CSIDL_PROGRAM_FILES 27 CSIDL_MYPICTURES // C:\Program Files\My Pictures 28 CSIDL_PROFILE // USERPROFILE 29 CSIDL_SYSTEMX86 // x86 system directory on RISC 2a CSIDL_PROGRAM_FILESX86 // x86 C:\Program Files on RISC 2b CSIDL_PROGRAM_FILES_COMMON // C:\Program Files\Common 2c CSIDL_PROGRAM_FILES_COMMONX86 // x86 Program Files\Common on RISC 2d CSIDL_COMMON_TEMPLATES // All Users\Templates 2e CSIDL_COMMON_DOCUMENTS // All Users\Documents 2f CSIDL_COMMON_ADMINTOOLS // All Users\Start Menu\Programs\Administrative Tools 30 CSIDL_ADMINTOOLS // \Start Menu\Programs\Administrative Tools 30 ssfPROGRAMFILESx86 Special Folder PROGRAM FILESx86 31 CSIDL_CONNECTIONS // Network and Dial-up Connections 32 33 34 35 CSIDL_COMMON_MUSIC // All Users\My Music 36 CSIDL_COMMON_PICTURES // All Users\My Pictures 37 CSIDL_COMMON_VIDEO // All Users\My Video 38 CSIDL_RESOURCES // %windir%\Resources\, For theme and other windows resources. 39 CSIDL_RESOURCES_LOCALIZED // %windir%\Resources\, for theme and other windows specific resources. 3a CSIDL_COMMON_OEM_LINKS // Links to All Users OEM specific apps 3b CSIDL_CDBURN_AREA // USERPROFILE\Local Settings\Application Data\Microsoft\CD Burning 3c 3d CSIDL_COMPUTERSNEARME // Computers Near Me (computered from Workgroup membership) 3e 3f 8000 CSIDL_FLAG_CREATE // combine with CSIDL_ value to force folder creation in SHGetFolderPath() 4000 CSIDL_FLAG_DONT_VERIFY // combine with CSIDL_ value to return an unverified folder path ff00 CSIDL_FLAG_MASK // mask for all possible flag values 1000 CSIDL_FLAG_NO_ALIAS // combine with CSIDL_ value to insure non-alias versions of the pidl 0800 CSIDL_FLAG_PER_USER_INIT // combine with CSIDL_ value to indicate per-user init (eg. upgrade) */ // // // * when operating on 1 file, do write error message #include #include #include #include #include "debug.h" #include "stringutils.h" #include "vectorutils.h" #include "csidlpaths.h" bool g_allowOverwrite= false; bool g_useStdout= false; bool g_bRecurse= false; bool g_bSysrootRelative= false; // relative to \\ | \\Storage | \\IPSM // 0 : no output // 1 : output unexpected errors // 2 : output all errors // 3 : output copied file names int verbose= 1; int nr_of_src_files= 0; #define AT_NONEXISTANT 1 #define AT_ISDIRECTORY 2 #define AT_ISFILE 3 int getWin32Attributes(const std::tstring& name) { WIN32_FIND_DATA wfd; HANDLE hFind = FindFirstFile( name.c_str(), &wfd); if (INVALID_HANDLE_VALUE == hFind) return AT_NONEXISTANT; FindClose( hFind); if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) return AT_ISDIRECTORY; return AT_ISFILE; } bool isWin32Directory(const std::tstring& name) { return getWin32Attributes(name)==AT_ISDIRECTORY; } bool isWin32File(const std::tstring& name) { return getWin32Attributes(name)==AT_ISFILE; } int getCeAttributes(const std::tstring& name) { DWORD dwAttr = CeGetFileAttributes( expand_csidl(ToWString(name)).c_str() ); if (0xFFFFFFFF == dwAttr) return AT_NONEXISTANT; if (dwAttr & FILE_ATTRIBUTE_DIRECTORY) return AT_ISDIRECTORY; return AT_ISFILE; } bool isCeDirectory(const std::tstring& name) { return getCeAttributes(name)==AT_ISDIRECTORY; } bool isCeFile(const std::tstring& name) { return getCeAttributes(name)==AT_ISFILE; } bool hasWildCards(const std::tstring& name) { return name.find_first_of(_T("*?"))!=name.npos; } std::tstring concat_path(const std::tstring& p1, const std::tstring& p2) { std::tstring result(p1); if (result.size() && result[result.size()-1]!='/' && result[result.size()-1]!='\\') result += '\\'; result += p2; return result; } std::tstring GetBasePath(const std::tstring& name) { size_t lastslash= name.find_last_of(_T("\\/")); if (lastslash==name.npos) return _T(""); return name.substr(0, lastslash); } std::tstring GetBaseName(const std::tstring& name) { size_t lastslash= name.find_last_of(_T("\\/")); if (lastslash==name.npos) return name; return name.substr(lastslash+1); } bool Win32FileGlob(const std::tstring& name, TStringList& list) { nr_of_src_files--; WIN32_FIND_DATA wfd; HANDLE hFind = FindFirstFile( name.c_str(), &wfd); if (INVALID_HANDLE_VALUE == hFind) { if (GetLastError()==ERROR_NO_MORE_FILES) { return true; } return false; } std::tstring rootpath= GetBasePath(name); do { if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { list.push_back(concat_path(rootpath, wfd.cFileName)); } } while (FindNextFile(hFind, &wfd)); FindClose(hFind); nr_of_src_files += list.size();; return true; } bool CeFileGlob(const std::tstring& name, TStringList& filelist, TStringList& dirlist) { nr_of_src_files--; CE_FIND_DATA wfd; HANDLE hFind = CeFindFirstFile( expand_csidl(ToWString(name)).c_str(), &wfd); if (INVALID_HANDLE_VALUE == hFind) { if (CeGetLastError()==ERROR_NO_MORE_FILES) return true; return false; } std::tstring rootpath= GetBasePath(name); do { if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { filelist.push_back(concat_path(rootpath, ToTString(wfd.cFileName))); } else if (ToWString(wfd.cFileName)!=L"." && ToWString(wfd.cFileName)!=L"..") { dirlist.push_back(concat_path(rootpath, ToTString(wfd.cFileName))); } } while (CeFindNextFile(hFind, &wfd)); CeFindClose(hFind); nr_of_src_files += filelist.size();; return true; } bool CopyWin32FileToCeFile(const std::tstring& src, const std::tstring& dstfile) { if (!g_allowOverwrite && isCeFile(dstfile)) { if ((nr_of_src_files==1 && verbose>0) || verbose>1) debug("destination file already exists - specify -f to overwrite\n"); return false; } HANDLE hSrc = CreateFile( src.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hSrc) { if ((nr_of_src_files==1 && verbose>0) || verbose>1) error("%hs", ToString(src).c_str()); return false; } HANDLE hDest = CeCreateFile( expand_csidl(ToWString(dstfile)).c_str(), GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hDest ) { if ((nr_of_src_files==1 && verbose>0) || verbose>1) ceerror("WCE:%hs", ToString(dstfile).c_str()); return false; } if (verbose>2) debug("Copying %hs to WCE:%hs\n", ToString(src).c_str(), ToString(dstfile).c_str()); ByteVector buffer; buffer.resize(65536); bool bRes= true; DWORD dwNumRead; do { if (!ReadFile( hSrc, vectorptr(buffer), buffer.size(), &dwNumRead, NULL)) { if (verbose>0) error("reading %hs", ToString(src).c_str()); bRes= false; break; } DWORD dwNumWritten; if (!CeWriteFile( hDest, vectorptr(buffer), dwNumRead, &dwNumWritten, NULL)) { if (verbose>0) ceerror("Writing WCE:%hs", ToString(dstfile).c_str()); bRes= false; break; } } while (dwNumRead); CeCloseHandle( hDest); CloseHandle (hSrc); return bRes; } bool CopyStdinToCeFile(const std::tstring& dstfile) { if (!g_allowOverwrite && isCeFile(dstfile)) { if ((nr_of_src_files==1 && verbose>0) || verbose>1) debug("destination file already exists - specify -f to overwrite\n"); return false; } HANDLE hDest = CeCreateFile( expand_csidl(ToWString(dstfile)).c_str(), GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hDest ) { if ((nr_of_src_files==1 && verbose>0) || verbose>1) ceerror("WCE:%hs", ToString(dstfile).c_str()); return false; } if (verbose>2) debug("Copying STDIN to WCE:%hs\n", ToString(dstfile).c_str()); ByteVector buffer; buffer.resize(65536); bool bRes= true; DWORD dwNumRead; while (!feof(stdin)) { dwNumRead= fread(vectorptr(buffer), 1, buffer.size(), stdin); if (dwNumRead==0) break; DWORD dwNumWritten; if (!CeWriteFile( hDest, vectorptr(buffer), dwNumRead, &dwNumWritten, NULL)) { if (verbose>0) ceerror("Writing WCE:%hs", ToString(dstfile).c_str()); bRes= false; break; } } CeCloseHandle( hDest); return bRes; } bool CopyCeFileToWin32File(const std::tstring& src, const std::tstring& dstfile) { if (!g_allowOverwrite && isWin32File(dstfile)) { if ((nr_of_src_files==1 && verbose>0) || verbose>1) debug("destination file already exists - specify -f to overwrite\n"); return false; } HANDLE hSrc = CeCreateFile( expand_csidl(ToWString(src)).c_str(), GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hSrc) { if ((nr_of_src_files==1 && verbose>0) || verbose>1) ceerror("WCE:%hs", ToString(src).c_str()); return false; } HANDLE hDest = CreateFile( dstfile.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hDest ) { if ((nr_of_src_files==1 && verbose>0) || verbose>1) error("%hs", ToString(dstfile).c_str()); return false; } if (verbose>2) debug("Copying WCE:%hs to %hs\n", ToString(src).c_str(), ToString(dstfile).c_str()); ByteVector buffer; buffer.resize(65536); bool bRes= true; DWORD dwNumRead; do { if (!CeReadFile( hSrc, vectorptr(buffer), buffer.size(), &dwNumRead, NULL)) { if (verbose>0) ceerror("reading WCE:%hs", ToString(src).c_str()); bRes= false; break; } DWORD dwNumWritten; if (!WriteFile( hDest, vectorptr(buffer), dwNumRead, &dwNumWritten, NULL)) { if (verbose>0) error("Writing %hs", ToString(dstfile).c_str()); bRes= false; break; } } while (dwNumRead); CloseHandle( hDest); CeCloseHandle (hSrc); return bRes; } bool PrintCeFile(const std::tstring& src) { HANDLE hSrc = CeCreateFile( expand_csidl(ToWString(src)).c_str(), GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hSrc) { if ((nr_of_src_files==1 && verbose>0) || verbose>1) ceerror("WCE:%hs", ToString(src).c_str()); return false; } if ((nr_of_src_files>1 && verbose>0) || verbose>1) debug("Printing WCE:%hs\n", ToString(src).c_str()); ByteVector buffer; buffer.resize(65536); bool bRes= true; DWORD dwNumRead; do { if (!CeReadFile( hSrc, vectorptr(buffer), buffer.size(), &dwNumRead, NULL)) { if (verbose>0) ceerror("Reading WCE:%hs", ToString(src).c_str()); bRes= false; break; } fwrite(vectorptr(buffer), 1, dwNumRead, stdout); } while (dwNumRead); CeCloseHandle (hSrc); printf("\n"); return bRes; } bool CopyWin32FileToCeDirectory(const std::tstring& src, const std::tstring& dstdir) { size_t lastslash= src.find_last_of(_T("\\/")); if (lastslash==src.npos) return CopyWin32FileToCeFile(src, concat_path(dstdir, src)); else return CopyWin32FileToCeFile(src, concat_path(dstdir, src.substr(lastslash+1))); } bool CopyCeFileToWin32Directory(const std::tstring& src, const std::tstring& dstdir) { size_t lastslash= src.find_last_of(_T("\\/")); if (lastslash==src.npos) return CopyCeFileToWin32File(src, concat_path(dstdir, src)); else return CopyCeFileToWin32File(src, concat_path(dstdir, src.substr(lastslash+1))); } bool CopyWin32ToCe(const TStringList& args, const std::tstring& dst) { bool bRes= true; nr_of_src_files += args.size(); if (isCeDirectory(dst)) { for (size_t i=0 ; i0) error("%hs\n", ToString(src).c_str()); return false; } for (size_t j= 0 ; j1) { if (verbose>0) debug("multiple source files: target must be an existing directory\n"); return false; } std::tstring src= args[0]; if (hasWildCards(src)) { TStringList files; if (!Win32FileGlob(src, files)) { if (verbose>0) error("%hs\n", ToString(src).c_str()); return false; } if (files.size()>1) { if (verbose>0) debug("source(%hs) is wildcard to multiple files: target(%hs) must be an existing directory\n", ToString(src).c_str(), ToString(dst).c_str()); return false; } src= files[0]; } bRes = (g_bRecurse||bRes) && CopyWin32FileToCeFile(src, dst); } return bRes; } bool CopyCeToWin32(const TStringList& args, const std::tstring& dst) { bool bRes= true; nr_of_src_files += args.size(); if (dst == _T("-")) { // output all to stdout for (size_t i=0 ; i0) error("WCE:%hs\n", ToString(src).c_str()); return false; } for (size_t j= 0 ; j0) error("WCE:%hs\n", ToString(src).c_str()); return false; } for (size_t j= 0 ; j1) { if (verbose>0) debug("multiple source files: target must be an existing directory\n"); return false; } std::tstring src= args[0]; if (isCeDirectory(src)) src= concat_path(src, _T("*")); if (hasWildCards(src)) { TStringList files, dirs; if (!CeFileGlob(src, files, dirs)) { if (verbose>0) error("WCE:%hs\n", ToString(src).c_str()); return false; } if (files.size()>1) { if (verbose>0) debug("source is wildcard to multiple files: target must be an existing directory\n"); return false; } src= files[0]; } bRes = (g_bRecurse||bRes) && CopyCeFileToWin32File(src, dst); } return bRes; } void usage(const std::string& cmd) { printf("(C) 2003-2008 Willem jan Hengeveld itsme@xs4all.nl\n"); if (cmd.substr(0,4)=="pput") { debug("Usage: pput [-f] \n"); debug(" -c : write stdin to file\n"); } else if (cmd.substr(0,4)=="pget") { debug("Usage: pget [-f] \n"); debug(" -c : print files to stdout\n"); } debug(" -f : overwrite existing files\n"); debug(" -r : recursive copy\n"); debug(" -q : less verbose output\n"); debug(" -v : more verbose output\n"); debug(" -l : list available special paths\n"); debug(" source files may contain wildcards\n"); } int main(int argc, char *argv[]) { std::string cmd= tolower(ToString(GetBaseName(ToTString(argv[0])))); bool do_list_csidl_paths= false; DebugStdOut(); TStringList args; for (int i=1 ; i