OSDN Git Service

Add prefix for file sizes.
[ffftp/ffftp.git] / filelist.c
old mode 100644 (file)
new mode 100755 (executable)
index 78bcb12..4cd3bd4
@@ -89,6 +89,7 @@ static void AddListView(HWND hWnd, int Pos, char *Name, int Type, LONGLONG Size,
 // 64ビット対応\r
 //static BOOL CALLBACK SelectDialogCallBack(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam);\r
 static INT_PTR CALLBACK SelectDialogCallBack(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam);\r
+static int GetImageIndex(int Win, int Pos);\r
 static void DispListList(FILELIST *Pos, char *Title);\r
 static void MakeRemoteTree1(char *Path, char *Cur, FILELIST **Base, int *CancelCheckWork);\r
 static void MakeRemoteTree2(char *Path, char *Cur, FILELIST **Base, int *CancelCheckWork);\r
@@ -97,12 +98,14 @@ static int GetListOneLine(char *Buf, int Max, FILE *Fd);
 static int MakeDirPath(char *Str, int ListType, char *Path, char *Dir);\r
 static void MakeLocalTree(char *Path, FILELIST **Base);\r
 static void AddFileList(FILELIST *Pkt, FILELIST **Base);\r
-static int AnalizeFileInfo(char *Str);\r
+static int AnalyzeFileInfo(char *Str);\r
 static int CheckUnixType(char *Str, char *Tmp, int Add1, int Add2, int Day);\r
 static int CheckHHMMformat(char *Str);\r
 static int CheckYYMMDDformat(char *Str, char Sym, int Dig3);\r
 static int CheckYYYYMMDDformat(char *Str, char Sym);\r
-static int ResolvFileInfo(char *Str, int ListType, char *Fname, LONGLONG *Size, FILETIME *Time, int *Attr, char *Owner, int *Link, int *InfoExist);\r
+// Windows Server 2008 R2\r
+static int CheckMMDDYYYYformat(char *Str, char Sym);\r
+static int ResolveFileInfo(char *Str, int ListType, char *Fname, LONGLONG *Size, FILETIME *Time, int *Attr, char *Owner, int *Link, int *InfoExist);\r
 static int FindField(char *Str, char *Buf, int Num, int ToLast);\r
 // MLSD対応\r
 static int FindField2(char *Str, char *Buf, char Separator, int Num, int ToLast);\r
@@ -141,6 +144,12 @@ extern int DotFile;
 extern int DispIgnoreHide;\r
 extern int DispDrives;\r
 extern int MoveMode;\r
+// ファイルアイコン表示対応\r
+extern int DispFileIcon;\r
+// タイムスタンプのバグ修正\r
+extern int DispTimeSeconds;\r
+// ファイルの属性を数字で表示\r
+extern int DispPermissionsNumber;\r
 \r
 /*===== ローカルなワーク =====*/\r
 \r
@@ -1294,9 +1303,9 @@ void GetRemoteDirForWnd(int Mode, int *CancelCheckWork)
 \r
                                while(GetListOneLine(Str, FMAX_PATH, fd) == FFFTP_SUCCESS)\r
                                {\r
-                                       if((ListType = AnalizeFileInfo(Str)) != LIST_UNKNOWN)\r
+                                       if((ListType = AnalyzeFileInfo(Str)) != LIST_UNKNOWN)\r
                                        {\r
-                                               if((Type = ResolvFileInfo(Str, ListType, Buf, &Size, &Time, &Attr, Owner, &Link, &InfoExist)) != NODE_NONE)\r
+                                               if((Type = ResolveFileInfo(Str, ListType, Buf, &Size, &Time, &Attr, Owner, &Link, &InfoExist)) != NODE_NONE)\r
                                                {\r
                                                        if(AskFilterStr(Buf, Type) == YES)\r
                                                        {\r
@@ -1363,7 +1372,7 @@ void RefreshIconImageList(FLISTANCHOR *Anchor)
        int i;\r
        char Cur[FMAX_PATH+1];\r
        SHFILEINFO FileInfo;\r
-       if(AskDispFileIcon() == YES)\r
+       if(DispFileIcon == YES)\r
        {\r
                SendMessage(hWndListLocal, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)NULL);\r
                ShowWindow(hWndListLocal, SW_SHOW);\r
@@ -1764,12 +1773,14 @@ static void AddListView(HWND hWnd, int Pos, char *Name, int Type, LONGLONG Size,
        else\r
                LvItem.iImage = 4;\r
        // ファイルアイコン表示対応\r
-       if(AskDispFileIcon() == YES && hWnd == GetLocalHwnd())\r
+       if(DispFileIcon == YES && hWnd == GetLocalHwnd())\r
                LvItem.iImage = ImageId + 5;\r
        LvItem.iItem = SendMessage(hWnd, LVM_INSERTITEM, 0, (LPARAM)&LvItem);\r
 \r
        /* 日付/時刻 */\r
-       FileTime2TimeString(Time, Tmp, DISPFORM_LEGACY, InfoExist);\r
+       // タイムスタンプのバグ修正\r
+//     FileTime2TimeString(Time, Tmp, DISPFORM_LEGACY, InfoExist);\r
+       FileTime2TimeString(Time, Tmp, DISPFORM_LEGACY, InfoExist, DispTimeSeconds);\r
        LvItem.mask = LVIF_TEXT;\r
        LvItem.iItem = Pos;\r
        LvItem.iSubItem = 1;\r
@@ -1813,7 +1824,9 @@ static void AddListView(HWND hWnd, int Pos, char *Name, int Type, LONGLONG Size,
 #else\r
                if(InfoExist & FINFO_ATTR)\r
 #endif\r
-                       AttrValue2String(Attr, Tmp);\r
+                       // ファイルの属性を数字で表示\r
+//                     AttrValue2String(Attr, Tmp);\r
+                       AttrValue2String(Attr, Tmp, DispPermissionsNumber);\r
                LvItem.mask = LVIF_TEXT;\r
                LvItem.iItem = Pos;\r
                LvItem.iSubItem = 4;\r
@@ -2337,6 +2350,58 @@ int GetNextSelected(int Win, int Pos, int All)
 }\r
 \r
 \r
+// ローカル側自動更新\r
+int GetHotSelected(int Win, char *Fname)\r
+{\r
+       HWND hWnd;\r
+       int Pos;\r
+\r
+       hWnd = GetLocalHwnd();\r
+       if(Win == WIN_REMOTE)\r
+               hWnd = GetRemoteHwnd();\r
+\r
+       Pos = SendMessage(hWnd, LVM_GETNEXTITEM, (WPARAM)-1, (LPARAM)MAKELPARAM(LVNI_FOCUSED, 0));\r
+       if(Pos != -1)\r
+               GetNodeName(Win, Pos, Fname, FMAX_PATH);\r
+\r
+       return Pos;\r
+}\r
+\r
+int SetHotSelected(int Win, char *Fname)\r
+{\r
+       HWND hWnd;\r
+       int i;\r
+       int Num;\r
+       char Name[FMAX_PATH+1];\r
+       LV_ITEM LvItem;\r
+       int Pos;\r
+\r
+       hWnd = GetLocalHwnd();\r
+       if(Win == WIN_REMOTE)\r
+               hWnd = GetRemoteHwnd();\r
+\r
+       Num = GetItemCount(Win);\r
+       memset(&LvItem, 0, sizeof(LV_ITEM));\r
+       Pos = -1;\r
+       for(i = 0; i < Num; i++)\r
+       {\r
+               LvItem.state = 0;\r
+               GetNodeName(Win, i, Name, FMAX_PATH);\r
+               if(_mbscmp(Fname, Name) == 0)\r
+               {\r
+                       Pos = i;\r
+                       LvItem.state = LVIS_FOCUSED;\r
+               }\r
+               LvItem.mask = LVIF_STATE;\r
+               LvItem.iItem = i;\r
+               LvItem.stateMask = LVIS_FOCUSED;\r
+               LvItem.iSubItem = 0;\r
+               SendMessage(hWnd, LVM_SETITEMSTATE, i, (LPARAM)&LvItem);\r
+       }\r
+\r
+       return Pos;\r
+}\r
+\r
 /*----- 指定された名前のアイテムを探す ----------------------------------------\r
 *\r
 *      Parameter\r
@@ -2575,6 +2640,35 @@ int GetNodeType(int Win, int Pos)
 }\r
 \r
 \r
+/*----- 指定位置のアイテムのイメージ番号を返す ----------------------------------------\r
+*\r
+*      Parameter\r
+*              int Win : ウインドウ番号 (WIN_xxx)\r
+*              int Pos : 位置\r
+*\r
+*      Return Value\r
+*              int イメージ番号\r
+*                      4 Symlink\r
+*----------------------------------------------------------------------------*/\r
+static int GetImageIndex(int Win, int Pos)\r
+{\r
+       HWND hWnd;\r
+       LV_ITEM LvItem;\r
+\r
+       hWnd = GetLocalHwnd();\r
+       if(Win == WIN_REMOTE)\r
+               hWnd = GetRemoteHwnd();\r
+\r
+       // 変数が未初期化のバグ修正\r
+       memset(&LvItem, 0, sizeof(LV_ITEM));\r
+       LvItem.mask = LVIF_IMAGE;\r
+       LvItem.iItem = Pos;\r
+       LvItem.iSubItem = 0;\r
+       SendMessage(hWnd, LVM_GETITEM, 0, (LPARAM)&LvItem);\r
+       return LvItem.iImage;\r
+}\r
+\r
+\r
 /*----- 指定位置のアイテムのオーナ名を返す ------------------------------------\r
 *\r
 *      Parameter\r
@@ -2756,26 +2850,44 @@ void MakeSelectedFileList(int Win, int Expand, int All, FILELIST **Base, int *Ca
 \r
                                        if(Ignore == NO)\r
                                        {\r
-                                               Pkt.Node = NODE_DIR;\r
+//                                             Pkt.Node = NODE_DIR;\r
+                                               if(GetImageIndex(Win, Pos) == 4) // symlink\r
+                                                       Pkt.Node = NODE_FILE;\r
+                                               else\r
+                                                       Pkt.Node = NODE_DIR;\r
                                                Pkt.Attr = 0;\r
                                                Pkt.Size = 0;\r
                                                memset(&Pkt.Time, 0, sizeof(FILETIME));\r
                                                AddFileList(&Pkt, Base);\r
 \r
-                                               if(Win == WIN_LOCAL)\r
-                                                       MakeLocalTree(Name, Base);\r
-                                               else\r
-                                               {\r
-                                                       AskRemoteCurDir(Cur, FMAX_PATH);\r
-\r
-                                                       if((AskListCmdMode() == NO) &&\r
-                                                          (AskUseNLST_R() == YES))\r
-                                                               MakeRemoteTree1(Name, Cur, Base, CancelCheckWork);\r
+//                                             if(Win == WIN_LOCAL)\r
+//                                                     MakeLocalTree(Name, Base);\r
+//                                             else\r
+//                                             {\r
+//                                                     AskRemoteCurDir(Cur, FMAX_PATH);\r
+//\r
+//                                                     if((AskListCmdMode() == NO) &&\r
+//                                                        (AskUseNLST_R() == YES))\r
+//                                                             MakeRemoteTree1(Name, Cur, Base, CancelCheckWork);\r
+//                                                     else\r
+//                                                             MakeRemoteTree2(Name, Cur, Base, CancelCheckWork);\r
+//                                             }\r
+                                               if(GetImageIndex(Win, Pos) != 4) { // symlink\r
+                                                       if(Win == WIN_LOCAL)\r
+                                                               MakeLocalTree(Name, Base);\r
                                                        else\r
-                                                               MakeRemoteTree2(Name, Cur, Base, CancelCheckWork);\r
+                                                       {\r
+                                                               AskRemoteCurDir(Cur, FMAX_PATH);\r
+\r
+                                                               if((AskListCmdMode() == NO) &&\r
+                                                                  (AskUseNLST_R() == YES))\r
+                                                                       MakeRemoteTree1(Name, Cur, Base, CancelCheckWork);\r
+                                                               else\r
+                                                                       MakeRemoteTree2(Name, Cur, Base, CancelCheckWork);\r
 \r
 //DispListList(*Base, "LIST");\r
 \r
+                                                       }\r
                                                }\r
                                        }\r
                                }\r
@@ -2994,14 +3106,21 @@ static void MakeRemoteTree2(char *Path, char *Cur, FILELIST **Base, int *CancelC
 \r
                                        /* まずディレクトリ名をセット */\r
                                        strcpy(Pkt.File, Pos->File);\r
-                                       Pkt.Node = NODE_DIR;\r
+//                                     Pkt.Node = NODE_DIR;\r
+                                       Pkt.Link = Pos->Link;\r
+                                       if(Pkt.Link == YES)\r
+                                               Pkt.Node = NODE_FILE;\r
+                                       else\r
+                                               Pkt.Node = NODE_DIR;\r
                                        Pkt.Size = 0;\r
                                        Pkt.Attr = 0;\r
                                        memset(&Pkt.Time, 0, sizeof(FILETIME));\r
                                        AddFileList(&Pkt, Base);\r
 \r
                                        /* そのディレクトリの中を検索 */\r
-                                       MakeRemoteTree2(Pos->File, Cur, Base, CancelCheckWork);\r
+//                                     MakeRemoteTree2(Pos->File, Cur, Base, CancelCheckWork);\r
+                                       if(Pkt.Link == NO)\r
+                                               MakeRemoteTree2(Pos->File, Cur, Base, CancelCheckWork);\r
                                }\r
                                Pos = Pos->Next;\r
                        }\r
@@ -3076,7 +3195,7 @@ void AddRemoteTreeToFileList(int Num, char *Path, int IncDir, FILELIST **Base)
 \r
                while(GetListOneLine(Str, FMAX_PATH, fd) == FFFTP_SUCCESS)\r
                {\r
-                       if((ListType = AnalizeFileInfo(Str)) == LIST_UNKNOWN)\r
+                       if((ListType = AnalyzeFileInfo(Str)) == LIST_UNKNOWN)\r
                        {\r
                                if(MakeDirPath(Str, ListType, Path, Dir) == FFFTP_SUCCESS)\r
                                {\r
@@ -3096,7 +3215,7 @@ void AddRemoteTreeToFileList(int Num, char *Path, int IncDir, FILELIST **Base)
                        }\r
                        else\r
                        {\r
-                               Node = ResolvFileInfo(Str, ListType, Name, &Size, &Time, &Attr, Owner, &Link, &InfoExist);\r
+                               Node = ResolveFileInfo(Str, ListType, Name, &Size, &Time, &Attr, Owner, &Link, &InfoExist);\r
 \r
                                if(AskFilterStr(Name, Node) == YES)\r
                                {\r
@@ -3285,7 +3404,10 @@ static void MakeLocalTree(char *Path, FILELIST **Base)
                                        Pkt.Attr = 0;\r
                                        Pkt.Time = FindBuf.ftLastWriteTime;\r
                                        FileTimeToSystemTime(&Pkt.Time, &TmpStime);\r
-                                       TmpStime.wSecond = 0;\r
+                                       // タイムスタンプのバグ修正\r
+//                                     TmpStime.wSecond = 0;\r
+                                       if(DispTimeSeconds == NO)\r
+                                               TmpStime.wSecond = 0;\r
                                        TmpStime.wMilliseconds = 0;\r
                                        SystemTimeToFileTime(&TmpStime, &Pkt.Time);\r
                                        AddFileList(&Pkt, Base);\r
@@ -3454,7 +3576,7 @@ FILELIST *SearchFileList(char *Fname, FILELIST *Base, int Caps)
 *              int リストタイプ (LIST_xxx)\r
 *----------------------------------------------------------------------------*/\r
 \r
-static int AnalizeFileInfo(char *Str)\r
+static int AnalyzeFileInfo(char *Str)\r
 {\r
        int Ret;\r
        char Tmp[FMAX_PATH+1];\r
@@ -3484,11 +3606,26 @@ static int AnalizeFileInfo(char *Str)
                Ret = LIST_SHIBASOKU;\r
        else\r
        {\r
+               // MLSD対応\r
+               if(FindField(Str, Tmp, 0, NO) == FFFTP_SUCCESS)\r
+               {\r
+                       _strlwr(Tmp);\r
+                       if(strstr(Tmp, "type=") != NULL)\r
+                       {\r
+                               if(FindField2(Str, Tmp, ';', 1, NO) == FFFTP_SUCCESS && FindField2(Str, Tmp, '=', 1, NO) == FFFTP_SUCCESS)\r
+                               {\r
+                                       Ret = LIST_MLSD;\r
+                               }\r
+                       }\r
+               }\r
+\r
                /* 以下のフォーマットをチェック */\r
                /* LIST_UNIX_10, LIST_UNIX_20, LIST_UNIX_12, LIST_UNIX_22, LIST_UNIX_50, LIST_UNIX_60 */\r
                /* MELCOM80 */\r
 \r
-               if(FindField(Str, Tmp, 0, NO) == FFFTP_SUCCESS)\r
+               // MLSD対応\r
+//             if(FindField(Str, Tmp, 0, NO) == FFFTP_SUCCESS)\r
+               if(Ret == LIST_UNKNOWN && FindField(Str, Tmp, 0, NO) == FFFTP_SUCCESS)\r
                {\r
                        /* MELCOM80は "d rwxrwxrwx" のようにスペースが空いている */\r
                        Flag1 = NO;\r
@@ -3601,6 +3738,13 @@ static int AnalizeFileInfo(char *Str)
 \r
                                if((Ret != LIST_UNKNOWN) && (Flag1 == YES))\r
                                        Ret |= LIST_MELCOM;\r
+\r
+                               // uClinux\r
+                               if((Ret == LIST_UNKNOWN) &&\r
+                                  (FindField(Str, Tmp, 5+Add1, NO) == FFFTP_SUCCESS))\r
+                               {\r
+                                       Ret = LIST_UNIX_17;\r
+                               }\r
                        }\r
                }\r
 \r
@@ -3747,6 +3891,27 @@ static int AnalizeFileInfo(char *Str)
                        }\r
                }\r
 \r
+               // Windows Server 2008 R2\r
+               if(Ret == LIST_UNKNOWN)\r
+               {\r
+                       if((FindField(Str, Tmp, 1, NO) == FFFTP_SUCCESS) &&\r
+                          (CheckHHMMformat(Tmp) == YES))\r
+                       {\r
+                               if((FindField(Str, Tmp, 2, NO) == FFFTP_SUCCESS) &&\r
+                                  ((Tmp[0] == '<') || (IsDigit(Tmp[0]) != 0)))\r
+                               {\r
+                                       if(FindField(Str, Tmp, 3, NO) == FFFTP_SUCCESS)\r
+                                       {\r
+                                               if((FindField(Str, Tmp, 0, NO) == FFFTP_SUCCESS) &&\r
+                                                  (CheckMMDDYYYYformat(Tmp, NUL) != 0))\r
+                                               {\r
+                                                       Ret = LIST_DOS_5;\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
                /* 以下のフォーマットをチェック */\r
                /* LIST_CHAMELEON */\r
 \r
@@ -3917,14 +4082,6 @@ static int AnalizeFileInfo(char *Str)
                }\r
 #endif\r
 \r
-               // MLSD対応\r
-               if(Ret == LIST_UNKNOWN)\r
-               {\r
-                       if(FindField2(Str, Tmp, ';', 1, NO) == FFFTP_SUCCESS && FindField2(Str, Tmp, '=', 1, NO) == FFFTP_SUCCESS)\r
-                       {\r
-                               Ret = LIST_MLSD;\r
-                       }\r
-               }\r
        }\r
 \r
 DoPrintf("ListType=%d", Ret);\r
@@ -4209,6 +4366,26 @@ static int CheckYYYYMMDDformat(char *Str, char Sym)
 }\r
 \r
 \r
+// Windows Server 2008 R2\r
+static int CheckMMDDYYYYformat(char *Str, char Sym)\r
+{\r
+       int Ret;\r
+\r
+       Ret = NO;\r
+       if((strlen(Str) == 10) &&\r
+          (IsDigitSym(Str[0], Sym) != 0) && (IsDigitSym(Str[1], Sym) != 0) &&\r
+          (IsDigit(Str[2]) == 0) &&\r
+          (IsDigitSym(Str[3], Sym) != 0) && (IsDigitSym(Str[4], Sym) != 0) &&\r
+          (IsDigit(Str[5]) == 0) &&\r
+          (IsDigitSym(Str[6], Sym) != 0) && (IsDigitSym(Str[7], Sym) != 0) &&\r
+          (IsDigitSym(Str[8], Sym) != 0) && (IsDigitSym(Str[9], Sym) != 0))\r
+       {\r
+               Ret = YES; \r
+       }\r
+       return(Ret);\r
+}\r
+\r
+\r
 /*----- ファイル情報からファイル名、サイズなどを取り出す ----------------------\r
 *\r
 *      Parameter\r
@@ -4226,7 +4403,7 @@ static int CheckYYYYMMDDformat(char *Str, char Sym)
 *              int 種類 (NODE_xxxx)\r
 *----------------------------------------------------------------------------*/\r
 \r
-static int ResolvFileInfo(char *Str, int ListType, char *Fname, LONGLONG *Size, FILETIME *Time, int *Attr, char *Owner, int *Link, int *InfoExist)\r
+static int ResolveFileInfo(char *Str, int ListType, char *Fname, LONGLONG *Size, FILETIME *Time, int *Attr, char *Owner, int *Link, int *InfoExist)\r
 {\r
        SYSTEMTIME sTime;\r
        SYSTEMTIME sTimeNow;\r
@@ -4357,6 +4534,48 @@ static int ResolvFileInfo(char *Str, int ListType, char *Fname, LONGLONG *Size,
                        }\r
                        break;\r
 \r
+               // Windows Server 2008 R2\r
+               case LIST_DOS_5 :\r
+                       *InfoExist |= (FINFO_TIME | FINFO_DATE | FINFO_SIZE);\r
+\r
+                       /* 日付 */\r
+                       FindField(Str, Buf, 0, NO);\r
+                       sTime.wMonth = atoi(Buf);\r
+                       sTime.wDay = atoi(Buf+3);\r
+                       sTime.wYear = atoi(Buf+6);\r
+\r
+                       /* 時刻 */\r
+                       FindField(Str, Buf, 1, NO);\r
+                       sTime.wHour = atoi(Buf);\r
+                       sTime.wMinute = atoi(Buf+3);\r
+                       sTime.wSecond = 0;\r
+                       sTime.wMilliseconds = 0;\r
+                       if(_strnicmp(Buf+5, "AM", 2) == 0)\r
+                       {\r
+                               if(sTime.wHour == 12)\r
+                                       sTime.wHour = 0;\r
+                       }\r
+                       else if(_strnicmp(Buf+5, "PM", 2) == 0)\r
+                       {\r
+                               if(sTime.wHour != 12)\r
+                                       sTime.wHour += 12;\r
+                       }\r
+                       SystemTimeToFileTime(&sTime, Time);\r
+                       SpecificLocalFileTime2FileTime(Time, AskHostTimeZone());\r
+\r
+                       /* サイズ */\r
+                       FindField(Str, Buf, 2, NO);\r
+                       *Size = _atoi64(Buf);\r
+\r
+                       /* 名前 */\r
+                       if(FindField(Str, Fname, 3, YES) == FFFTP_SUCCESS)\r
+                       {\r
+                               Ret = NODE_FILE;\r
+                               if(Buf[0] == '<')\r
+                                       Ret = NODE_DIR;\r
+                       }\r
+                       break;\r
+\r
                case LIST_OS2 :\r
                        *InfoExist |= (FINFO_DATE | FINFO_SIZE);\r
 \r
@@ -4990,6 +5209,9 @@ static int ResolvFileInfo(char *Str, int ListType, char *Fname, LONGLONG *Size,
                        // 不完全な実装のホストが存在するため以下の形式も許容\r
                        // fact1=value1;fact2=value2;fact3=value3 filename\r\n\r
                        // fact1=value1;fact2=value2;fact3=value3;filename\r\n\r
+                       // SymlinkはRFC3659の7.7.4. A More Complex Exampleに\r
+                       // よるとtype=OS.unix=slink:(target)だが\r
+                       // ProFTPDはtype=OS.unix=symlink:(target)となる\r
                case LIST_MLSD:\r
                        {\r
                                int i = 0;\r
@@ -4997,6 +5219,7 @@ static int ResolvFileInfo(char *Str, int ListType, char *Fname, LONGLONG *Size,
                                char Fact[FMAX_PATH + 1];\r
                                char Name[FMAX_PATH + 1];\r
                                char Value[FMAX_PATH + 1];\r
+                               char Value2[FMAX_PATH + 1];\r
                                char* pFileName;\r
                                strncpy(StrBuf, Str, FMAX_PATH * 2);\r
                                StrBuf[FMAX_PATH * 2] = '\0';\r
@@ -5027,6 +5250,12 @@ static int ResolvFileInfo(char *Str, int ListType, char *Fname, LONGLONG *Size,
                                                                Ret = NODE_DIR;\r
                                                        else if(_stricmp(Value, "file") == 0)\r
                                                                Ret = NODE_FILE;\r
+                                                       else if(_stricmp(Value, "OS.unix") == 0)\r
+                                                               if(FindField2(Fact, Value2, '=', 2, NO) == FFFTP_SUCCESS)\r
+                                                                       if(_stricmp(Value2, "symlink") == 0 || _stricmp(Value2, "slink") == 0) { // ProFTPD is symlink. A example of RFC3659 is slink.\r
+                                                                               Ret = NODE_DIR;\r
+                                                                               *Link = YES;\r
+                                                                       }\r
                                                }\r
                                                else if(_stricmp(Name, "size") == 0)\r
                                                {\r
@@ -5091,6 +5320,8 @@ static int ResolvFileInfo(char *Str, int ListType, char *Fname, LONGLONG *Size,
 //             case LIST_MELCOM :\r
                // linux-ftpd\r
                case LIST_UNIX_16 :\r
+               // uClinux\r
+               case LIST_UNIX_17 :\r
                default:\r
                        /* offsはサイズの位置, offs=0はカラム4 */\r
                        offs = 0;\r
@@ -5146,6 +5377,9 @@ static int ResolvFileInfo(char *Str, int ListType, char *Fname, LONGLONG *Size,
                           (ListType == LIST_UNIX_73) ||\r
                           (ListType == LIST_UNIX_16))\r
                                offs2 = -1;\r
+                       // uClinux\r
+                       if(ListType == LIST_UNIX_17)\r
+                               offs2 = -3;\r
 \r
                        /* offs3はオーナ名の位置 */\r
                        offs3 = 0;\r
@@ -5176,6 +5410,9 @@ static int ResolvFileInfo(char *Str, int ListType, char *Fname, LONGLONG *Size,
                           (ListType == LIST_UNIX_74) ||\r
                           (ListType == LIST_UNIX_75))\r
                                Flag2 = 1;\r
+                       // uClinux\r
+                       if(ListType == LIST_UNIX_17)\r
+                               Flag2 = -1;\r
 \r
                        *InfoExist |= (FINFO_DATE | FINFO_SIZE | FINFO_ATTR);\r
 \r
@@ -5273,6 +5510,11 @@ static int ResolvFileInfo(char *Str, int ListType, char *Fname, LONGLONG *Size,
                                        }\r
                                }\r
                        }\r
+                       // uClinux\r
+                       else if(Flag2 == -1)\r
+                       {\r
+                               *InfoExist &= ~(FINFO_DATE | FINFO_TIME);\r
+                       }\r
                        else\r
                        {\r
                                /* LIST_UNIX_?4, LIST_UNIX_?5 の時 */\r
@@ -5902,7 +6144,7 @@ static int atoi_n(const char *Str, int Len)
 \r
 // UTF-8対応\r
 // ファイル一覧から漢字コードを推測\r
-// 優先度はUTF-8、Shift_JIS、EUC、JISの順\r
+// å\84ªå\85\88度ã\81¯UTF-8ã\80\81Shift_JISã\80\81EUCã\80\81JISã\80\81UTF-8 HFS+ã\81®é \86\r
 int AnalyzeNameKanjiCode(int Num)\r
 {\r
        char Str[FMAX_PATH+1];\r
@@ -5922,7 +6164,11 @@ int AnalyzeNameKanjiCode(int Num)
        int PointJIS;\r
        int PointEUC;\r
        int PointUTF8N;\r
+       int PointUTF8HFSX;\r
        char* p;\r
+       CODECONVINFO cInfo1;\r
+       CODECONVINFO cInfo2;\r
+       char Buf[FMAX_PATH+1];\r
 \r
        NameKanjiCode = KANJI_AUTO;\r
        Point = 0;\r
@@ -5930,15 +6176,16 @@ int AnalyzeNameKanjiCode(int Num)
        PointJIS = 0;\r
        PointEUC = 0;\r
        PointUTF8N = 0;\r
+       PointUTF8HFSX = 0;\r
        MakeCacheFileName(Num, Str);\r
        if((fd = fopen(Str, "rb")) != NULL)\r
        {\r
                while(GetListOneLine(Str, FMAX_PATH, fd) == FFFTP_SUCCESS)\r
                {\r
-                       if((ListType = AnalizeFileInfo(Str)) != LIST_UNKNOWN)\r
+                       if((ListType = AnalyzeFileInfo(Str)) != LIST_UNKNOWN)\r
                        {\r
                                strcpy(Name, "");\r
-                               Node = ResolvFileInfo(Str, ListType | LIST_RAW_NAME, Name, &Size, &Time, &Attr, Owner, &Link, &InfoExist);\r
+                               Node = ResolveFileInfo(Str, ListType | LIST_RAW_NAME, Name, &Size, &Time, &Attr, Owner, &Link, &InfoExist);\r
                                p = Name;\r
                                while(*p != '\0')\r
                                {\r
@@ -5951,28 +6198,56 @@ int AnalyzeNameKanjiCode(int Num)
                                }\r
                                if(!p)\r
                                {\r
+                                       // ASCII文字の範囲外\r
                                        if(!CheckStringM(Name))\r
-                                               PointUTF8N++;\r
-                                       else\r
                                        {\r
-                                               switch(CheckKanjiCode(Name, strlen(Name), KANJI_SJIS))\r
-                                               {\r
-                                               case KANJI_SJIS:\r
-                                                       PointSJIS++;\r
-                                                       break;\r
-                                               case KANJI_JIS:\r
-                                                       PointJIS++;\r
-                                                       break;\r
-                                               case KANJI_EUC:\r
-                                                       PointEUC++;\r
-                                                       break;\r
-                                               }\r
+                                               InitCodeConvInfo(&cInfo1);\r
+                                               cInfo1.KanaCnv = NO;\r
+                                               cInfo1.Str = Name;\r
+                                               cInfo1.StrLen = strlen(Name);\r
+                                               cInfo1.Buf = Buf;\r
+                                               cInfo1.BufSize = FMAX_PATH;\r
+                                               cInfo2 = cInfo1;\r
+                                               ConvUTF8NtoUTF8HFSX(&cInfo1);\r
+                                               ConvUTF8HFSXtoUTF8N(&cInfo2);\r
+                                               if(cInfo1.OutLen > (int)strlen(Name))\r
+                                                       PointUTF8N++;\r
+                                               else\r
+                                                       PointUTF8HFSX++;\r
+                                               if(cInfo2.OutLen < (int)strlen(Name))\r
+                                                       PointUTF8HFSX++;\r
+                                               else\r
+                                                       PointUTF8N++;\r
+                                       }\r
+                                       switch(CheckKanjiCode(Name, strlen(Name), KANJI_SJIS))\r
+                                       {\r
+                                       case KANJI_SJIS:\r
+                                               PointSJIS++;\r
+                                               break;\r
+                                       case KANJI_EUC:\r
+                                               PointEUC++;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               else\r
+                               {\r
+                                       // ASCII文字の範囲内\r
+                                       switch(CheckKanjiCode(Name, strlen(Name), KANJI_SJIS))\r
+                                       {\r
+                                       case KANJI_JIS:\r
+                                               PointJIS++;\r
+                                               break;\r
                                        }\r
                                }\r
                        }\r
                }\r
                fclose(fd);\r
        }\r
+       if(PointUTF8HFSX >= Point)\r
+       {\r
+               NameKanjiCode = KANJI_UTF8HFSX;\r
+               Point = PointUTF8HFSX;\r
+       }\r
        if(PointJIS >= Point)\r
        {\r
                NameKanjiCode = KANJI_JIS;\r