167 lines
3.3 KiB
Go
167 lines
3.3 KiB
Go
package fat
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// checksumShortName returns the checksum for the shortname that is used
|
|
// for the long name entries.
|
|
func checksumShortName(name string) uint8 {
|
|
var sum uint8 = name[0]
|
|
for i := uint8(1); i < 11; i++ {
|
|
sum = name[i] + (((sum & 1) << 7) + ((sum & 0xFE) >> 1))
|
|
}
|
|
|
|
return sum
|
|
}
|
|
|
|
// generateShortName takes a list of existing short names and a long
|
|
// name and generates the next valid short name. This process is done
|
|
// according to the MS specification.
|
|
func generateShortName(longName string, used []string) (string, error) {
|
|
longName = strings.ToUpper(longName)
|
|
|
|
// Split the string at the final "."
|
|
dotIdx := strings.LastIndex(longName, ".")
|
|
|
|
var ext string
|
|
if dotIdx == -1 {
|
|
dotIdx = len(longName)
|
|
} else {
|
|
ext = longName[dotIdx+1 : len(longName)]
|
|
}
|
|
|
|
ext = cleanShortString(ext)
|
|
ext = ext[0:len(ext)]
|
|
rawName := longName[0:dotIdx]
|
|
name := cleanShortString(rawName)
|
|
simpleName := fmt.Sprintf("%s.%s", name, ext)
|
|
if ext == "" {
|
|
simpleName = simpleName[0 : len(simpleName)-1]
|
|
}
|
|
|
|
doSuffix := name != rawName || len(name) > 8
|
|
if !doSuffix {
|
|
for _, usedSingle := range used {
|
|
if strings.ToUpper(usedSingle) == simpleName {
|
|
doSuffix = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if doSuffix {
|
|
found := false
|
|
for i := 1; i < 99999; i++ {
|
|
serial := fmt.Sprintf("~%d", i)
|
|
|
|
nameOffset := 8 - len(serial)
|
|
if len(name) < nameOffset {
|
|
nameOffset = len(name)
|
|
}
|
|
|
|
serialName := fmt.Sprintf("%s%s", name[0:nameOffset], serial)
|
|
simpleName = fmt.Sprintf("%s.%s", serialName, ext)
|
|
|
|
exists := false
|
|
for _, usedSingle := range used {
|
|
if strings.ToUpper(usedSingle) == simpleName {
|
|
exists = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !exists {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
return "", fmt.Errorf("could not generate short name for %s", longName)
|
|
}
|
|
}
|
|
|
|
return simpleName, nil
|
|
}
|
|
|
|
// shortNameEntryValue returns the proper formatted short name value
|
|
// for the directory cluster entry.
|
|
func shortNameEntryValue(name string) string {
|
|
var shortParts []string
|
|
if name == "." || name == ".." {
|
|
shortParts = []string{name, ""}
|
|
} else {
|
|
shortParts = strings.Split(name, ".")
|
|
}
|
|
|
|
if len(shortParts) == 1 {
|
|
shortParts = append(shortParts, "")
|
|
}
|
|
|
|
if len(shortParts[0]) < 8 {
|
|
var temp bytes.Buffer
|
|
temp.WriteString(shortParts[0])
|
|
for i := 0; i < 8-len(shortParts[0]); i++ {
|
|
temp.WriteRune(' ')
|
|
}
|
|
|
|
shortParts[0] = temp.String()
|
|
}
|
|
|
|
if len(shortParts[1]) < 3 {
|
|
var temp bytes.Buffer
|
|
temp.WriteString(shortParts[1])
|
|
for i := 0; i < 3-len(shortParts[1]); i++ {
|
|
temp.WriteRune(' ')
|
|
}
|
|
|
|
shortParts[1] = temp.String()
|
|
}
|
|
|
|
return fmt.Sprintf("%s%s", shortParts[0], shortParts[1])
|
|
}
|
|
|
|
func cleanShortString(v string) string {
|
|
var result bytes.Buffer
|
|
for _, char := range v {
|
|
// We skip these chars
|
|
if char == '.' || char == ' ' {
|
|
continue
|
|
}
|
|
|
|
if !validShortChar(char) {
|
|
char = '_'
|
|
}
|
|
|
|
result.WriteRune(char)
|
|
}
|
|
|
|
return result.String()
|
|
}
|
|
|
|
func validShortChar(char rune) bool {
|
|
if char >= 'A' && char <= 'Z' {
|
|
return true
|
|
}
|
|
|
|
if char >= '0' && char <= '9' {
|
|
return true
|
|
}
|
|
|
|
validShortSymbols := []rune{
|
|
'_', '^', '$', '~', '!', '#', '%', '&', '-', '{', '}', '(',
|
|
')', '@', '\'', '`',
|
|
}
|
|
|
|
for _, valid := range validShortSymbols {
|
|
if char == valid {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|