diff --git a/include/dos_system.h b/include/dos_system.h index 3d31ab94..babc2cad 100644 --- a/include/dos_system.h +++ b/include/dos_system.h @@ -130,6 +130,8 @@ public: void Flush(void); FILE * fhandle; //todo handle this properly private: + localFile(const localFile&); // prevent copying + localFile& operator= (const localFile&); // prevent assignment bool read_only_medium; enum { NONE,READ,WRITE } last_action; }; @@ -172,11 +174,17 @@ public: class CFileInfo { public: - CFileInfo(void) { - orgname[0] = shortname[0] = 0; - isOverlayDir = isDir = false; - id = MAX_OPENDIRS; - nextEntry = shortNr = 0; + CFileInfo(void) + : orgname{0}, + shortname{0}, + isOverlayDir(false), + isDir(false), + id(MAX_OPENDIRS), + nextEntry(0), + shortNr(0), + fileList(0), + longNameList(0) + { } ~CFileInfo(void) { for (Bit32u i=0; i +#include +#include #include #include -#include #ifndef DOSBOX_DOSBOX_H #include "dosbox.h" #endif @@ -33,6 +34,27 @@ #define strncasecmp(a,b,n) _strnicmp(a,b,n) #endif +/// Copy a string into C array +/// +/// This function copies string pointed by src to fixed-size buffer dst. +/// At most N bytes from src are copied, where N is size of dst. +/// If exactly N bytes are copied, then terminating null byte is put +/// into buffer, thus buffer overrun is prevented. +/// +/// Function returns pointer to buffer to be compatible with std::strcpy. +/// +/// Usage: +/// +/// char buffer[2]; +/// safe_strcpy(buffer, "abc"); +/// // buffer is filled with "a" + +template +char * safe_strcpy(char (& dst)[N], const char * src) noexcept { + snprintf(dst, N, "%s", src); + return & dst[0]; +} + #define safe_strncpy(a,b,n) do { strncpy((a),(b),(n)-1); (a)[(n)-1] = 0; } while (0) #ifdef HAVE_STRINGS_H diff --git a/src/dos/drive_cache.cpp b/src/dos/drive_cache.cpp index 9bd548e6..f175b88e 100644 --- a/src/dos/drive_cache.cpp +++ b/src/dos/drive_cache.cpp @@ -22,7 +22,8 @@ #include "support.h" #include "cross.h" -// STL stuff +// System includes +#include #include #include #include @@ -60,45 +61,62 @@ bool SortByDirNameRev(DOS_Drive_Cache::CFileInfo* const &a, DOS_Drive_Cache::CFi return strcmp(a->shortname,b->shortname)>0; } -DOS_Drive_Cache::DOS_Drive_Cache(void) { - dirBase = new CFileInfo; - save_dir = 0; - srchNr = 0; - label[0] = 0; - nextFreeFindFirst = 0; - for (Bit32u i=0; iid=0; + dir->id = 0; return 0; } void DOS_Drive_Cache::SetBaseDir(const char* baseDir) { + // Guard if source and destination are the same + if (basePath == baseDir) { + return; + } + + safe_strcpy(basePath, baseDir); Bit16u id; - strcpy(basePath,baseDir); if (OpenDir(baseDir,id)) { char* result = 0; ReadDir(id,result); @@ -162,15 +185,15 @@ void DOS_Drive_Cache::SetBaseDir(const char* baseDir) { } void DOS_Drive_Cache::ExpandName(char* path) { - strcpy(path,GetExpandName(path)); + safe_strncpy(path, GetExpandName(path), CROSS_LEN); } char* DOS_Drive_Cache::GetExpandName(const char* path) { static char work [CROSS_LEN] = { 0 }; - char dir [CROSS_LEN]; + char dir [CROSS_LEN]; work[0] = 0; - strcpy (dir,path); + safe_strcpy (dir, path); const char* pos = strrchr(path,CROSS_FILESPLIT); @@ -179,9 +202,9 @@ char* DOS_Drive_Cache::GetExpandName(const char* path) { if (pos) { // Last Entry = File - strcpy(dir,pos+1); - GetLongName(dirInfo, dir); - strcat(work,dir); + safe_strcpy(dir, pos+1); + (void) GetLongName(dirInfo, dir, sizeof(dir)); // ignore the return code + strncat(work, dir, sizeof(work) - strlen(work) - 1); } if (*work) { @@ -206,20 +229,20 @@ void DOS_Drive_Cache::AddEntry(const char* path, bool checkExists) { CFileInfo* dir = FindDirInfo(path,expand); const char* pos = strrchr(path,CROSS_FILESPLIT); - if (pos) { - strcpy(file,pos+1); + if (pos && dir) { + safe_strcpy(file, pos+1); // Check if file already exists, then don't add new entry... if (checkExists) { - if (GetLongName(dir,file)>=0) return; + if (GetLongName(dir, file, sizeof(file))>=0) return; } CreateEntry(dir,file,false); - Bits index = GetLongName(dir,file); + Bits index = GetLongName(dir, file, sizeof(file)); if (index>=0) { Bit32u i; // Check if there are any open search dir that are affected by this... - if (dir) for (i=0; inextEntry)) dirSearch[i]->nextEntry++; } @@ -236,7 +259,7 @@ void DOS_Drive_Cache::AddEntryDirOverlay(const char* path, bool checkExists) { char dironly[CROSS_LEN + 1]; //When adding a directory, the directory we want to operate inside in is the above it. (which can go wrong if the directory already exists.) - strcpy(dironly,path); + safe_strcpy(dironly, path); char* post = strrchr(dironly,CROSS_FILESPLIT); if (post) { @@ -255,11 +278,11 @@ void DOS_Drive_Cache::AddEntryDirOverlay(const char* path, bool checkExists) { CFileInfo* dir = FindDirInfo(dironly,expand); const char* pos = strrchr(path,CROSS_FILESPLIT); - if (pos) { - strcpy(file,pos + 1); + if (pos && dir) { + safe_strcpy(file, pos + 1); // Check if directory already exists, then don't add new entry... if (checkExists) { - Bits index = GetLongName(dir,file); + Bits index = GetLongName(dir, file, sizeof(file)); if (index >= 0) { //directory already exists, but most likely empty. dir = dir->fileList[index]; @@ -276,11 +299,11 @@ void DOS_Drive_Cache::AddEntryDirOverlay(const char* path, bool checkExists) { CreateEntry(dir,file,true); - Bits index = GetLongName(dir,file); + Bits index = GetLongName(dir, file, sizeof(file)); if (index>=0) { Bit32u i; // Check if there are any open search dir that are affected by this... - if (dir) for (i=0; inextEntry)) dirSearch[i]->nextEntry++; } @@ -320,11 +343,12 @@ void DOS_Drive_Cache::CacheOut(const char* path, bool ignoreLastDir) { char tmp[CROSS_LEN] = { 0 }; Bit32s len=0; const char* pos = strrchr(path,CROSS_FILESPLIT); - if (pos) len = (Bit32s)(pos - path); - if (len>0) { - safe_strncpy(tmp,path,len+1); + if (pos) + len = (Bit32s)(pos - path); + if (len>0) { + safe_strncpy(tmp,path,len+1); } else { - strcpy(tmp,path); + safe_strcpy(tmp, path); } dir = FindDirInfo(tmp,expand); } else { @@ -335,13 +359,15 @@ void DOS_Drive_Cache::CacheOut(const char* path, bool ignoreLastDir) { // delete file objects... //Maybe check if it is a file and then only delete the file and possibly the long name. instead of all objects in the dir. for(Bit32u i=0; ifileList.size(); i++) { - if (dirSearch[srchNr]==dir->fileList[i]) dirSearch[srchNr] = 0; - DeleteFileInfo(dir->fileList[i]); dir->fileList[i] = 0; + if (dirSearch[srchNr]==dir->fileList[i]) + dirSearch[srchNr] = nullptr; + DeleteFileInfo(dir->fileList[i]); + dir->fileList[i] = nullptr; } // clear lists dir->fileList.clear(); dir->longNameList.clear(); - save_dir = 0; + save_dir = nullptr; } bool DOS_Drive_Cache::IsCachedIn(CFileInfo* curDir) { @@ -355,10 +381,14 @@ bool DOS_Drive_Cache::GetShortName(const char* fullname, char* shortname) { CFileInfo* curDir = FindDirInfo(fullname,expand); const char* pos = strrchr(fullname,CROSS_FILESPLIT); - if (pos) pos++; else return false; + if (pos) + pos++; + else + return false; std::vector::size_type filelist_size = curDir->longNameList.size(); - if (GCC_UNLIKELY(filelist_size<=0)) return false; + if (GCC_UNLIKELY(filelist_size<=0)) + return false; // The orgname part of the list is not sorted (shortname is)! So we can only walk through it. for(Bitu i = 0; i < filelist_size; i++) { @@ -367,7 +397,7 @@ bool DOS_Drive_Cache::GetShortName(const char* fullname, char* shortname) { #else if (strcmp(pos,curDir->longNameList[i]->orgname) == 0) { #endif - strcpy(shortname,curDir->longNameList[i]->shortname); + safe_strncpy(shortname, curDir->longNameList[i]->shortname, DOS_NAMELENGTH_ASCII); return true; } } @@ -498,7 +528,7 @@ static Bits wine_hash_short_file_name( char* name, char* buffer ) } #endif -Bits DOS_Drive_Cache::GetLongName(CFileInfo* curDir, char* shortName) { +Bits DOS_Drive_Cache::GetLongName(CFileInfo* curDir, char* shortName, const size_t shortName_len) { std::vector::size_type filelist_size = curDir->fileList.size(); if (GCC_UNLIKELY(filelist_size<=0)) return -1; @@ -514,7 +544,7 @@ Bits DOS_Drive_Cache::GetLongName(CFileInfo* curDir, char* shortName) { if (res>0) low = mid+1; else if (res<0) high = mid-1; else { // Found - strcpy(shortName,curDir->fileList[mid]->orgname); + safe_strncpy(shortName, curDir->fileList[mid]->orgname, shortName_len); return mid; }; } @@ -528,7 +558,7 @@ Bits DOS_Drive_Cache::GetLongName(CFileInfo* curDir, char* shortName) { buff[res] = 0; if (!strcmp(shortName,buff)) { // Found - strcpy(shortName,curDir->fileList[i]->orgname); + safe_strncpy(shortName, curDir->fileList[i]->orgname, shortName_len); return (Bits)i; } } @@ -557,7 +587,9 @@ void DOS_Drive_Cache::CreateShortName(CFileInfo* curDir, CFileInfo* info) { char* tmpName = tmpNameBuffer; // Remove Spaces - strcpy(tmpName,info->orgname); + // avoid using safe_strncpy to prevent GCC warning about truncation on an incomplete copy + strncpy(tmpName, info->orgname, CROSS_LEN); + tmpName[CROSS_LEN - 1] = '\0'; // zero-terminate even if the source wasn't upcase(tmpName); createShort = RemoveSpaces(tmpName); @@ -565,45 +597,52 @@ void DOS_Drive_Cache::CreateShortName(CFileInfo* curDir, CFileInfo* info) { char* pos = strchr(tmpName,'.'); if (pos) { // ignore preceding '.' if extension is longer than "3" - if (strlen(pos)>4) { + if (strlen(pos) > 4) { while (*tmpName=='.') tmpName++; createShort = true; } pos = strchr(tmpName,'.'); - if (pos) len = (Bits)(pos - tmpName); - else len = (Bits)strlen(tmpName); + if (pos) + len = pos - tmpName; + else + len = (Bits)strlen(tmpName); } else { - len = (Bits)strlen(tmpName); + len = strlen(tmpName); } // Should shortname version be created ? createShort = createShort || (len>8); if (!createShort) { char buffer[CROSS_LEN]; - strcpy(buffer,tmpName); - createShort = (GetLongName(curDir,buffer)>=0); + safe_strcpy(buffer, tmpName); + createShort = (GetLongName(curDir, buffer, sizeof(buffer)) >= 0); } if (createShort) { // Create number char buffer[8]; info->shortNr = CreateShortNameID(curDir,tmpName); - sprintf(buffer,"%d",info->shortNr); + sprintf(buffer,"%" PRIuPTR, info->shortNr); // Copy first letters Bits tocopy = 0; size_t buflen = strlen(buffer); - if (len+buflen+1>8) tocopy = (Bits)(8 - buflen - 1); - else tocopy = len; - safe_strncpy(info->shortname,tmpName,tocopy+1); + if (len + buflen + 1 > 8) + tocopy = (Bits)(8 - buflen - 1); + else + tocopy = len; + // Copy the lesser of "DOS_NAMELENGTH_ASCII" or "tocopy + 1" characters. + safe_strncpy(info->shortname, tmpName, + tocopy < DOS_NAMELENGTH_ASCII ? tocopy + 1 : DOS_NAMELENGTH_ASCII); // Copy number - strcat(info->shortname,"~"); - strcat(info->shortname,buffer); + strncat(info->shortname, "~", DOS_NAMELENGTH_ASCII - strlen(info->shortname) - 1); + strncat(info->shortname, buffer, DOS_NAMELENGTH_ASCII - strlen(info->shortname) - 1); // Add (and cut) Extension, if available if (pos) { // Step to last extension... - pos = strrchr(tmpName, '.'); + pos = strrchr(tmpName, '.'); // extensions are at-most 3 chars (4 with terminator) // add extension - strncat(info->shortname,pos,4); + unsigned int remaining_space = DOS_NAMELENGTH_ASCII - strlen(info->shortname) - 1; + strncat(info->shortname, pos, 4 < remaining_space ? 4 : remaining_space); info->shortname[DOS_NAMELENGTH] = 0; } @@ -631,7 +670,7 @@ void DOS_Drive_Cache::CreateShortName(CFileInfo* curDir, CFileInfo* info) { curDir->longNameList.push_back(info); } } else { - strcpy(info->shortname,tmpName); + safe_strncpy(info->shortname, tmpName, DOS_NAMELENGTH_ASCII); } RemoveTrailingDot(info->shortname); } @@ -648,7 +687,7 @@ DOS_Drive_Cache::CFileInfo* DOS_Drive_Cache::FindDirInfo(const char* path, char* Bit16u id; if (save_dir && (strcmp(path,save_path)==0)) { - strcpy(expandedPath,save_expanded); + safe_strncpy(expandedPath, save_expanded, CROSS_LEN); return save_dir; }; @@ -656,33 +695,37 @@ DOS_Drive_Cache::CFileInfo* DOS_Drive_Cache::FindDirInfo(const char* path, char* // Remove base dir path start += strlen(basePath); - strcpy(expandedPath,basePath); + safe_strncpy(expandedPath, basePath, CROSS_LEN); // hehe, baseDir should be cached in... if (!IsCachedIn(curDir)) { - strcpy(work,basePath); + safe_strcpy(work, basePath); if (OpenDir(curDir,work,id)) { char buffer[CROSS_LEN]; char* result = 0; - strcpy(buffer,dirPath); + safe_strcpy(buffer, dirPath); ReadDir(id,result); - strcpy(dirPath,buffer); + safe_strcpy(dirPath, buffer); if (dirSearch[id]) { dirSearch[id]->id = MAX_OPENDIRS; - dirSearch[id] = 0; + dirSearch[id] = nullptr; } }; }; do { -// bool errorcheck = false; pos = strchr(start,CROSS_FILESPLIT); - if (pos) { safe_strncpy(dir,start,pos-start+1); /*errorcheck = true;*/ } - else { strcpy(dir,start); }; + if (pos) { + safe_strncpy(dir, start, + static_cast(pos - start) < sizeof(dir) ? pos - start + 1 : sizeof(dir)); + } + else { + safe_strcpy(dir, start); + }; // Path found - Bits nextDir = GetLongName(curDir,dir); - strcat(expandedPath,dir); + Bits nextDir = GetLongName(curDir, dir, sizeof(dir)); + strncat(expandedPath, dir, CROSS_LEN - strlen(expandedPath) - 1); // Error check /* if ((errorcheck) && (nextDir<0)) { @@ -692,30 +735,30 @@ DOS_Drive_Cache::CFileInfo* DOS_Drive_Cache::FindDirInfo(const char* path, char* // Follow Directory if ((nextDir>=0) && curDir->fileList[nextDir]->isDir) { curDir = curDir->fileList[nextDir]; - strcpy (curDir->orgname,dir); + safe_strcpy(curDir->orgname, dir); if (!IsCachedIn(curDir)) { if (OpenDir(curDir,expandedPath,id)) { char buffer[CROSS_LEN]; char* result = 0; - strcpy(buffer,dirPath); + safe_strcpy(buffer, dirPath); ReadDir(id,result); - strcpy(dirPath,buffer); + safe_strcpy(dirPath, buffer); if (dirSearch[id]) { dirSearch[id]->id = MAX_OPENDIRS; - dirSearch[id] = 0; + dirSearch[id] = nullptr; } }; } }; if (pos) { - strcat(expandedPath,split); + strncat(expandedPath, split, CROSS_LEN - strlen(expandedPath) - 1); start = pos+1; } } while (pos); // Save last result for faster access next time - strcpy(save_path,path); - strcpy(save_expanded,expandedPath); + safe_strcpy(save_path, path); + safe_strcpy(save_expanded, expandedPath); save_dir = curDir; return curDir; @@ -735,10 +778,12 @@ bool DOS_Drive_Cache::OpenDir(CFileInfo* dir, const char* expand, Bit16u& id) { id = GetFreeID(dir); dirSearch[id] = dir; char expandcopy [CROSS_LEN]; - strcpy(expandcopy,expand); + safe_strcpy(expandcopy, expand); // Add "/" char end[2]={CROSS_FILESPLIT,0}; - if (expandcopy[strlen(expandcopy)-1]!=CROSS_FILESPLIT) strcat(expandcopy,end); + if (expandcopy[strlen(expandcopy)-1] != CROSS_FILESPLIT) { + strncat(expandcopy, end, sizeof(expandcopy) - strlen(expandcopy) - 1); + } // open dir if (dirSearch[id]) { // open dir @@ -746,12 +791,12 @@ bool DOS_Drive_Cache::OpenDir(CFileInfo* dir, const char* expand, Bit16u& id) { if (dirp || dir->isOverlayDir) { // Reset it.. if (dirp) close_directory(dirp); - strcpy(dirPath,expandcopy); + safe_strcpy(dirPath, expandcopy); return true; } if (dirSearch[id]) { dirSearch[id]->id = MAX_OPENDIRS; - dirSearch[id] = 0; + dirSearch[id] = nullptr; } }; return false; @@ -759,7 +804,7 @@ bool DOS_Drive_Cache::OpenDir(CFileInfo* dir, const char* expand, Bit16u& id) { void DOS_Drive_Cache::CreateEntry(CFileInfo* dir, const char* name, bool is_directory) { CFileInfo* info = new CFileInfo; - strcpy(info->orgname, name); + safe_strcpy(info->orgname, name); info->shortNr = 0; info->isDir = is_directory; @@ -795,8 +840,8 @@ void DOS_Drive_Cache::CreateEntry(CFileInfo* dir, const char* name, bool is_dire void DOS_Drive_Cache::CopyEntry(CFileInfo* dir, CFileInfo* from) { CFileInfo* info = new CFileInfo; // just copy things into new fileinfo - strcpy(info->orgname, from->orgname); - strcpy(info->shortname, from->shortname); + safe_strcpy(info->orgname, from->orgname); + safe_strcpy(info->shortname, from->shortname); info->shortNr = from->shortNr; info->isDir = from->isDir; @@ -805,7 +850,8 @@ void DOS_Drive_Cache::CopyEntry(CFileInfo* dir, CFileInfo* from) { bool DOS_Drive_Cache::ReadDir(Bit16u id, char* &result) { // shouldnt happen... - if (id>MAX_OPENDIRS) return false; + if (id >= MAX_OPENDIRS) + return false; if (!IsCachedIn(dirSearch[id])) { // Try to open directory @@ -813,7 +859,7 @@ bool DOS_Drive_Cache::ReadDir(Bit16u id, char* &result) { if (!dirp) { if (dirSearch[id]) { dirSearch[id]->id = MAX_OPENDIRS; - dirSearch[id] = 0; + dirSearch[id] = nullptr; } return false; } @@ -843,7 +889,7 @@ bool DOS_Drive_Cache::ReadDir(Bit16u id, char* &result) { if (SetResult(dirSearch[id], result, dirSearch[id]->nextEntry)) return true; if (dirSearch[id]) { dirSearch[id]->id = MAX_OPENDIRS; - dirSearch[id] = 0; + dirSearch[id] = nullptr; } return false; } @@ -856,7 +902,7 @@ bool DOS_Drive_Cache::SetResult(CFileInfo* dir, char* &result, Bitu entryNr) if (entryNr>=dir->fileList.size()) return false; CFileInfo* info = dir->fileList[entryNr]; // copy filename, short version - strcpy(res,info->shortname); + safe_strcpy(res, info->shortname); // Set to next Entry dir->nextEntry = entryNr+1; return true; @@ -872,7 +918,7 @@ bool DOS_Drive_Cache::FindFirst(char* path, Bit16u& id) { //If the next one isn't free, move on to the next, if none is free => reset and assume the worst Bit16u local_findcounter = 0; while ( local_findcounter < MAX_OPENDIRS ) { - if (dirFindFirst[this->nextFreeFindFirst] == 0) break; + if (dirFindFirst[this->nextFreeFindFirst] == nullptr) break; if (++this->nextFreeFindFirst >= MAX_OPENDIRS) this->nextFreeFindFirst = 0; //Wrap around local_findcounter++; } @@ -889,12 +935,13 @@ bool DOS_Drive_Cache::FindFirst(char* path, Bit16u& id) { for(Bitu n=0; n nextEntry = 0; + dirFindFirst[dirFindFirstID]-> nextEntry = 0; // Copy entries to use with FindNext for (Bitu i=0; ifileList.size(); i++) { @@ -923,7 +970,8 @@ bool DOS_Drive_Cache::FindNext(Bit16u id, char* &result) { } if (!SetResult(dirFindFirst[id], result, dirFindFirst[id]->nextEntry)) { // free slot - DeleteFileInfo(dirFindFirst[id]); dirFindFirst[id] = 0; + DeleteFileInfo(dirFindFirst[id]); + dirFindFirst[id] = nullptr; return false; } return true; @@ -935,13 +983,14 @@ void DOS_Drive_Cache::ClearFileInfo(CFileInfo *dir) { ClearFileInfo(info); } if (dir->id != MAX_OPENDIRS) { - dirSearch[dir->id] = 0; + dirSearch[dir->id] = nullptr; dir->id = MAX_OPENDIRS; } } void DOS_Drive_Cache::DeleteFileInfo(CFileInfo *dir) { - if (dir) + if (dir) { ClearFileInfo(dir); - delete dir; + delete dir; + } } diff --git a/src/dos/drives.h b/src/dos/drives.h index 2cb0654b..f4627dc0 100644 --- a/src/dos/drives.h +++ b/src/dos/drives.h @@ -185,6 +185,8 @@ public: imageDisk *loadedDisk; bool created_successfully; private: + fatDrive(const fatDrive&); // prevent copying + fatDrive& operator= (const fatDrive&); // prevent assignment Bit32u getClusterValue(Bit32u clustNum); void setClusterValue(Bit32u clustNum, Bit32u clustValue); Bit32u getClustFirstSect(Bit32u clustNum); @@ -408,6 +410,8 @@ public: virtual Bits UnMount(void); virtual char const* GetLabel(void); private: + Virtual_Drive(const Virtual_Drive&); // prevent copying + Virtual_Drive& operator= (const Virtual_Drive&); // prevent assignment VFILE_Block * search_file; };