static BOOL RenameFile(RDWRHandle handle, struct DirectoryPosition* pos, struct DirectoryEntry* entry, CLUSTER firstcluster) { BOOL retval; int counter=0; for (;;) { retval = LoFileNameExists(handle, firstcluster, entry->filename, entry->extension); if (retval == FALSE) break; if (retval == FAIL) return FALSE; counter++; sprintf(entry->extension, "%03d", counter); if (IsCurrentDir(*entry)) { memcpy(entry->filename, "DOT ", 8); } if (IsPreviousDir(*entry)) { memcpy(entry->filename, "DOTDOT ", 8); } } return WriteDirectory(handle, pos, entry); }
STATIC BOOL SubdirGetter(RDWRHandle handle, struct DirectoryPosition* pos, void** buffer) { struct DirectoryEntry entry; struct Pipe** pipe = (struct Pipe**) buffer; handle = handle; if (!GetDirectory(handle, pos, &entry)) return FAIL; if (IsLFNEntry(&entry) || (IsDeletedLabel(entry)) || (IsCurrentDir(entry)) || (IsPreviousDir(entry))) { return TRUE; } if (entry.attribute & FA_DIREC) { if ((*pipe)->n == (*pipe)->counter) { memcpy((*pipe)->pos, pos, sizeof(struct DirectoryPosition)); return FALSE; } (*pipe)->counter++; } return TRUE; }
void MemorySortEntries(struct DirectoryEntry* entries, int amofentries) { int i=0, realentries = 0; struct DirectoryEntry* temp = entries; SetResourceConfiguration(&MemConfig); if (amofentries == 0) return; if (IsCurrentDir(entries[0])) { if (amofentries == 1) return; entries++; i++; } if (IsPreviousDir(entries[0])) { entries++; i++; } for (; i < amofentries; i++) if (IsLFNEntry(&temp[i]) == 0) realentries++; if (realentries) SelectionSortEntries(entries, realentries); }
BOOL DiskSortEntries(RDWRHandle handle, CLUSTER cluster) { int i=0; long totalcount, lfncount, realcount; struct DiskEntryGetterStruct parameters; struct DirectoryPosition pos; struct DirectoryEntry entry; parameters.handle = handle; parameters.cluster = cluster; SetResourceConfiguration(&DiskConfig); totalcount = low_dircount(handle, cluster, 0xffff); if (totalcount == -1) RETURN_FTEERR(FALSE); lfncount = low_dircount(handle, cluster, LFN_ATTRIBUTES); if (lfncount == -1) RETURN_FTEERR(FALSE); realcount = totalcount - lfncount; for (i = 0; i < 2; i++) { if (!GetNthDirectoryPosition(handle, cluster, i, &pos)) { RETURN_FTEERR(FALSE); } if (!GetDirectory(handle, &pos, &entry)) { RETURN_FTEERR(FALSE); } switch (i) { case 0: if (IsCurrentDir(entry)) { realcount--; } break; case 1: if (IsPreviousDir(entry)) { realcount--; } } } if (realcount && realcount <= INT_MAX) SelectionSortEntries(¶meters, (int)realcount); return TRUE; }
BOOL GetNthSubDirectoryPosition(RDWRHandle handle, CLUSTER cluster, unsigned long n, struct DirectoryPosition* result) { int counter = 0; struct DirectoryPosition pos; struct DirectoryEntry* entry; entry = AllocateDirectoryEntry(); if (!entry) return FALSE; n++; /* n is 0 based */ while (n) { pos.sector = 0; pos.offset = 0; if (!GetNthDirectoryPosition(handle, cluster, counter++, &pos)) { FreeDirectoryEntry(entry); return FALSE; } if ((pos.sector == 0) && (pos.offset == 0)) /* Not found*/ { FreeDirectoryEntry(entry); return TRUE; } if (!GetDirectory(handle, &pos, entry)) { FreeDirectoryEntry(entry); return TRUE; } if (!IsLFNEntry((entry)) && (entry->attribute & FA_DIREC) && (!IsDeletedLabel(*entry)) && (!IsCurrentDir(*entry)) && (!IsPreviousDir(*entry))) { n--; } } memcpy(result, &pos, sizeof(struct DirectoryPosition)); FreeDirectoryEntry(entry); return TRUE; }
static int entrygetter (RDWRHandle handle, struct DirectoryPosition* pos, void** buffer) { struct Pipe** pipe = (struct Pipe**) buffer; struct DirectoryEntry entry; if (!GetDirectory(handle, pos, &entry)) { RETURN_FTEERR(FAIL); } if (IsCurrentDir(entry) || IsPreviousDir(entry)) { return TRUE; } if ((*pipe)->entrynr == (*pipe)->ecounter) { if ((*pipe)->slotorentry == ENTRY) { memcpy((*pipe)->entry, &entry, sizeof(struct DirectoryEntry)); RETURN_FTEERR(FALSE); } else { if ((*pipe)->slot == (*pipe)->scounter) { memcpy((*pipe)->entry, &entry, sizeof(struct DirectoryEntry)); RETURN_FTEERR(FALSE); } (*pipe)->scounter++; return TRUE; } } if ((entry.attribute & FA_LABEL) == 0) (*pipe)->ecounter++; return TRUE; }
BOOL CheckEntryForInvalidChars(RDWRHandle handle, struct DirectoryPosition* pos, struct DirectoryEntry* direct, char* filename, BOOL fixit) { int i; BOOL invalidname = FALSE; BOOL InRoot; struct DirectoryEntry entry; memcpy(&entry, direct, sizeof(struct DirectoryEntry)); if (((entry.attribute & FA_LABEL) == 0) && /* Not checking volume labels */ !IsDeletedLabel(entry)) { if (IsPreviousDir(entry) || /* .. */ IsCurrentDir(entry)) /* . */ { /* See wether the given directory entry is in the root directory */ InRoot = IsRootDirPosition(handle, pos); if (InRoot == FAIL) return FAIL; /* All the '.' and '..' entries must be directories */ if (((entry.attribute & FA_DIREC) == 0) || (InRoot)) { if (IsCurrentDir(entry)) { if (InRoot) { ShowFileNameViolation(handle, "", "The root directory contains an '.' entry"); } else { ShowParentViolation(handle, filename, "%s contains an '.' entry that is not a directory"); } memcpy(entry.filename, "DOT ", 8); } else { if (InRoot) { ShowFileNameViolation(handle, "", "The root directory contains an '..' entry"); } else { ShowParentViolation(handle, filename, "%s contains an '..' entry that is not a directory"); } memcpy(entry.filename, "DOTDOT ", 8); } if (fixit) { memcpy(entry.extension, " ", 3); if (!RenameFile(handle, pos, &entry, DirCluster)) /* Write the changes to disk */ return FAIL; } return FALSE; } /* Check wether you realy have '.' and '..' */ if (IsCurrentDir(entry)) { if ((memcmp(entry.filename, ". ", 8) != 0) || (memcmp(entry.extension, " ", 3) != 0)) { ShowFileNameViolation(handle, filename, "%s contains invalid char(s)"); if (fixit) { memcpy(entry.filename, ". ", 8); memcpy(entry.extension, " ", 3); if (!RenameFile(handle, pos, &entry, DirCluster)) /* Write the changes to disk */ return FAIL; } } } if (IsPreviousDir(entry)) { if ((memcmp(entry.filename, ".. ", 8) != 0) || (memcmp(entry.extension, " ", 3) != 0)) { ShowFileNameViolation(handle, filename, "%s contains invalid char(s)"); if (fixit) { memcpy(entry.filename, ".. ", 8); memcpy(entry.extension, " ", 3); if (!RenameFile(handle, pos, &entry, DirCluster)) /* Write the changes to disk */ return FAIL; } } } } else { if (entry.filename[0] == ' ') { invalidname = TRUE; entry.filename[0] = 'A'; } /* file name */ for (i = 0; i < 8; i++) { if ((strchr(INVALIDSFNCHARS, entry.filename[i])) || (((unsigned char)(entry.filename[i]) < 0x20) && (entry.filename[i] != 0x05)) || (islower(entry.filename[i]))) { entry.filename[i] = 'A'; invalidname = TRUE; } } /* extension */ for (i = 0; i < 3; i++) { if ((strchr(INVALIDSFNCHARS, entry.extension[i])) || (((unsigned char)(entry.extension[i]) < 0x20) && (entry.extension[i] != 0x05)) || (islower(entry.extension[i]))) { entry.extension[i] = 'A'; invalidname = TRUE; } } if (invalidname) { ShowFileNameViolation(handle, filename, "%s contains invalid char(s)"); if (fixit) { if (!RenameFile(handle, pos, &entry, DirCluster)) /* Write the changes to disk */ return FAIL; } return FALSE; } } } return TRUE; }
static BOOL FilesSummaryGetter(RDWRHandle handle, struct DirectoryPosition* position, struct DirectoryEntry* entry, void** structure) { CLUSTER firstcluster; struct FilesSummary** info = (struct FilesSummary**) structure; unsigned long dirsize=0, *pdirsize = &dirsize, bytespercluster, labelsinfat; position = position; bytespercluster = GetSectorsPerCluster(handle) * BYTESPERSECTOR; if (!bytespercluster) return FAIL; if (entry->attribute & FA_LABEL) return TRUE; if (IsLFNEntry(entry)) return TRUE; if (IsDeletedLabel(*entry)) return TRUE; if (entry->attribute & FA_DIREC) { if (IsCurrentDir(*entry)) return TRUE; if (IsPreviousDir(*entry)) return TRUE; (*info)->DirectoryCount++; labelsinfat = GetLabelsInFat(handle); if (!labelsinfat) return FAIL; fatmap = CreateBitField(labelsinfat); if (!fatmap) return FAIL; firstcluster = GetFirstCluster(entry); if (!TraverseSubdir(handle, firstcluster, DirSizeGetter, (void**) &pdirsize, FALSE)) { return FAIL; } DestroyBitfield(fatmap); AddUlongLong(&(*info)->SizeOfDirectories[0],dirsize); return TRUE; /* Not taking directories into account when gathering information on files. */ } (*info)->TotalFileCount++; AddUlongLong(&(*info)->TotalSizeofFiles[0],entry->filesize); AddUlongLong(&(*info)->SizeOfAllFiles[0], CalculateClustersSize(entry->filesize, bytespercluster)); if (entry->attribute & FA_SYSTEM) { (*info)->SystemFileCount++; AddUlongLong(&(*info)->SizeOfSystemFiles[0], CalculateClustersSize(entry->filesize, bytespercluster)); } if (entry->attribute & FA_HIDDEN) { (*info)->HiddenFileCount++; AddUlongLong(&(*info)->SizeOfHiddenFiles[0], CalculateClustersSize(entry->filesize, bytespercluster)); } return TRUE; }
bool Path::ParsePathString (UCS2String& volume, vector<UCS2String>& dirnames, UCS2String& filename, const UCS2String& path) { UCS2String stash; // Unless noted otherwise, all components are considered empty. volume.clear(); dirnames.clear(); filename.clear(); // Empty strings are considered valid path names, too. if (path.empty() == true) return true; UCS2String::const_iterator i = path.begin(); // Check for a volume identifier: // - If the second character is a colon, we presume the first two characters to identify the drive. In that case // we'll also check whether the following character is a path separator, indicating an absolute path on that // drive, in which case we'll also include a trailing separator to the drive letter. // - If the path starts with two identical path separator characters, we presume the string to be a UNC path, in // which case we set the volume identifier to the network share, including two leading and a trailing separator // characters. // - Otherwise, if the first character is a path separator, this indicates an absolute path on the current drive, // in which case we set the volume identifier to a single path separator character. // - In any other case, we presume the string to be a relative path, and set the volume identifier to an empty // string. if ((*i == POV_PATH_SEPARATOR) || (*i == POV_PATH_SEPARATOR_2)) { // String starts with a path separator; may be an absolute path on the current drive or a UNC path. // Stash the separator (use the canonical one, not the one actually used). stash += POV_PATH_SEPARATOR; ++i; if ((i != path.end()) && (*i == stash[0])) { // The second character is also an (identical) separator character, indicating a UNC path. // Stash another path separators (use the canonical one, not the one actually used). stash += POV_PATH_SEPARATOR; ++i; // Stash everything that follows, up to the next path separator. for (; (i != path.end()) && (*i != POV_PATH_SEPARATOR) && (*i != POV_PATH_SEPARATOR_2); ++i) stash += *i; // Currently, we don't support bare UNC share names without trailing separator character, // even though allegedly they are technically valid. if (i == path.end()) return false; // Stash another path separator (use the canonical one, not the one actually used) // to indicate an absolute path. stash += POV_PATH_SEPARATOR; ++i; } // If it's not a UNC path, at this point our stash contains a single path separator, // which is exactly what we intend to emit as the volume identifier in that case. // Emit whatever string we have stashed as the volume identifier. volume = stash; stash.clear(); } else if (isalpha (*i)) { // String starts with an ASCII letter; may be a relative path or a drive letter. // Stash the character, then go on to test what's next. stash += *i; ++i; if ((i != path.end()) && (*i == ':')) { // Yup, that's a drive letter. Add the colon to the stashed letter. stash += ':'; ++i; // Currently, we don't support relative paths if a volume is specified. if ((i == path.end()) || ((*i != POV_PATH_SEPARATOR) && (*i != POV_PATH_SEPARATOR_2))) return false; // Stash another path separator (use the canonical one, not the one actually used) // to indicate an absolute path. stash += POV_PATH_SEPARATOR; ++i; // Emit the stashed string as the volume identifier. volume = stash; stash.clear(); } // If it's not a drive letter, at this point we have only stashed the first letter, but // our index still points to the second one so the following algorithm will take care of it. } // Walk through the path string, stashing any non-separator characters. Whenever we hit a separator // character, emit the stashed characters (if any) as a directory name and clear the stash. // Also, as we go along, resolve the special directory names `.` and `..` if possible. // NB since we do not emit "empty" directory names, any sequence of consecutive separator // characters is effectively treated as a single separator character. for(; i != path.end(); ++i) { if ((*i == POV_PATH_SEPARATOR) || (*i == POV_PATH_SEPARATOR_2)) { if (!stash.empty() && !IsCurrentDir(stash)) { if (!dirnames.empty() && IsParentDir(stash)) dirnames.pop_back(); else dirnames.push_back (stash); stash.clear(); } } else stash += *i; } // Whatever is left in the stash is presumably the actual file name. // NB as a consequence of the algorithm chosen, any path name ending in a path separator // character will be emitted as a list of directories only, with the file name left empty. filename = stash; return true; }