📄 tclwinfile.c
字号:
TclWinResolveShortcut(bufferPtr) Tcl_DString *bufferPtr; /* Holds name of file to resolve. On * return, holds resolved file name. */{ HRESULT hres; IShellLink *psl; IPersistFile *ppf; WIN32_FIND_DATA wfd; WCHAR wpath[MAX_PATH]; char *path, *ext; char realFileName[MAX_PATH]; /* * Windows system calls do not automatically resolve * shortcuts like UNIX automatically will with symbolic links. */ path = Tcl_DStringValue(bufferPtr); ext = strrchr(path, '.'); if ((ext == NULL) || (stricmp(ext, ".lnk") != 0)) { return 0; } CoInitialize(NULL); path = Tcl_DStringValue(bufferPtr); realFileName[0] = '\0'; hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl); if (SUCCEEDED(hres)) { hres = psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, &ppf); if (SUCCEEDED(hres)) { MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, sizeof(wpath)); hres = ppf->lpVtbl->Load(ppf, wpath, STGM_READ); if (SUCCEEDED(hres)) { hres = psl->lpVtbl->Resolve(psl, NULL, SLR_ANY_MATCH | SLR_NO_UI); if (SUCCEEDED(hres)) { hres = psl->lpVtbl->GetPath(psl, realFileName, MAX_PATH, &wfd, 0); } } ppf->lpVtbl->Release(ppf); } psl->lpVtbl->Release(psl); } CoUninitialize(); if (realFileName[0] != '\0') { Tcl_DStringSetLength(bufferPtr, 0); Tcl_DStringAppend(bufferPtr, realFileName, -1); return 1; } return 0;}#endifTcl_Obj* TclpObjGetCwd(interp) Tcl_Interp *interp;{ Tcl_DString ds; if (TclpGetCwd(interp, &ds) != NULL) { Tcl_Obj *cwdPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1); Tcl_IncrRefCount(cwdPtr); Tcl_DStringFree(&ds); return cwdPtr; } else { return NULL; }}int TclpObjAccess(pathPtr, mode) Tcl_Obj *pathPtr; int mode;{ return NativeAccess((CONST TCHAR*) Tcl_FSGetNativePath(pathPtr), mode);}int TclpObjLstat(pathPtr, statPtr) Tcl_Obj *pathPtr; Tcl_StatBuf *statPtr; { /* * Ensure correct file sizes by forcing the OS to write any * pending data to disk. This is done only for channels which are * dirty, i.e. have been written to since the last flush here. */ TclWinFlushDirtyChannels (); return NativeStat((CONST TCHAR*) Tcl_FSGetNativePath(pathPtr), statPtr, 1);}#ifdef S_IFLNKTcl_Obj* TclpObjLink(pathPtr, toPtr, linkAction) Tcl_Obj *pathPtr; Tcl_Obj *toPtr; int linkAction;{ if (toPtr != NULL) { int res; TCHAR* LinkTarget = (TCHAR*)Tcl_FSGetNativePath(toPtr); TCHAR* LinkSource = (TCHAR*)Tcl_FSGetNativePath(pathPtr); if (LinkSource == NULL || LinkTarget == NULL) { return NULL; } res = WinLink(LinkSource, LinkTarget, linkAction); if (res == 0) { return toPtr; } else { return NULL; } } else { TCHAR* LinkSource = (TCHAR*)Tcl_FSGetNativePath(pathPtr); if (LinkSource == NULL) { return NULL; } return WinReadLink(LinkSource); }}#endif/* *--------------------------------------------------------------------------- * * TclpFilesystemPathType -- * * This function is part of the native filesystem support, and * returns the path type of the given path. Returns NTFS or FAT * or whatever is returned by the 'volume information' proc. * * Results: * NULL at present. * * Side effects: * None. * *--------------------------------------------------------------------------- */Tcl_Obj*TclpFilesystemPathType(pathObjPtr) Tcl_Obj* pathObjPtr;{#define VOL_BUF_SIZE 32 int found; char volType[VOL_BUF_SIZE]; char* firstSeparator; CONST char *path; Tcl_Obj *normPath = Tcl_FSGetNormalizedPath(NULL, pathObjPtr); if (normPath == NULL) return NULL; path = Tcl_GetString(normPath); if (path == NULL) return NULL; firstSeparator = strchr(path, '/'); if (firstSeparator == NULL) { found = tclWinProcs->getVolumeInformationProc( Tcl_FSGetNativePath(pathObjPtr), NULL, 0, NULL, NULL, NULL, (WCHAR *)volType, VOL_BUF_SIZE); } else { Tcl_Obj *driveName = Tcl_NewStringObj(path, firstSeparator - path+1); Tcl_IncrRefCount(driveName); found = tclWinProcs->getVolumeInformationProc( Tcl_FSGetNativePath(driveName), NULL, 0, NULL, NULL, NULL, (WCHAR *)volType, VOL_BUF_SIZE); Tcl_DecrRefCount(driveName); } if (found == 0) { return NULL; } else { Tcl_DString ds; Tcl_Obj *objPtr; Tcl_WinTCharToUtf(volType, -1, &ds); objPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds),Tcl_DStringLength(&ds)); Tcl_DStringFree(&ds); return objPtr; }#undef VOL_BUF_SIZE}/* *--------------------------------------------------------------------------- * * TclpObjNormalizePath -- * * This function scans through a path specification and replaces it, * in place, with a normalized version. This means using the * 'longname', and expanding any symbolic links contained within the * path. * * Results: * The new 'nextCheckpoint' value, giving as far as we could * understand in the path. * * Side effects: * The pathPtr string, which must contain a valid path, is * possibly modified in place. * *--------------------------------------------------------------------------- */intTclpObjNormalizePath(interp, pathPtr, nextCheckpoint) Tcl_Interp *interp; Tcl_Obj *pathPtr; int nextCheckpoint;{ char *lastValidPathEnd = NULL; /* This will hold the normalized string */ Tcl_DString dsNorm; char *path; char *currentPathEndPosition; Tcl_DStringInit(&dsNorm); path = Tcl_GetString(pathPtr); if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_WINDOWS) { /* * We're on Win95, 98 or ME. There are two assumptions * in this block of code. First that the native (NULL) * encoding is basically ascii, and second that symbolic * links are not possible. Both of these assumptions * appear to be true of these operating systems. */ Tcl_Obj *temp = NULL; int isDrive = 1; Tcl_DString ds; currentPathEndPosition = path + nextCheckpoint; while (1) { char cur = *currentPathEndPosition; if ((cur == '/' || cur == 0) && (path != currentPathEndPosition)) { /* Reached directory separator, or end of string */ CONST char *nativePath = Tcl_UtfToExternalDString(NULL, path, currentPathEndPosition - path, &ds); /* * Now we convert the tail of the current path to its * 'long form', and append it to 'dsNorm' which holds * the current normalized path, if the file exists. */ if (isDrive) { if (GetFileAttributesA(nativePath) == 0xffffffff) { /* File doesn't exist */ Tcl_DStringFree(&ds); break; } if (nativePath[0] >= 'a') { ((char*)nativePath)[0] -= ('a' - 'A'); } Tcl_DStringAppend(&dsNorm,nativePath,Tcl_DStringLength(&ds)); } else { WIN32_FIND_DATA fData; HANDLE handle; handle = FindFirstFileA(nativePath, &fData); if (handle == INVALID_HANDLE_VALUE) { if (GetFileAttributesA(nativePath) == 0xffffffff) { /* File doesn't exist */ Tcl_DStringFree(&ds); break; } /* This is usually the '/' in 'c:/' at end of string */ Tcl_DStringAppend(&dsNorm,"/", 1); } else { char *nativeName; if (fData.cFileName[0] != '\0') { nativeName = fData.cFileName; } else { nativeName = fData.cAlternateFileName; } FindClose(handle); Tcl_DStringAppend(&dsNorm,"/", 1); Tcl_DStringAppend(&dsNorm,nativeName,-1); } } Tcl_DStringFree(&ds); lastValidPathEnd = currentPathEndPosition; if (cur == 0) { break; } /* * If we get here, we've got past one directory * delimiter, so we know it is no longer a drive */ isDrive = 0; } currentPathEndPosition++; } } else { /* We're on WinNT or 2000 or XP */ Tcl_Obj *temp = NULL; int isDrive = 1; Tcl_DString ds; currentPathEndPosition = path + nextCheckpoint; while (1) { char cur = *currentPathEndPosition; if ((cur == '/' || cur == 0) && (path != currentPathEndPosition)) { /* Reached directory separator, or end of string */ WIN32_FILE_ATTRIBUTE_DATA data; CONST char *nativePath = Tcl_WinUtfToTChar(path, currentPathEndPosition - path, &ds); if ((*tclWinProcs->getFileAttributesExProc)(nativePath, GetFileExInfoStandard, &data) != TRUE) { /* File doesn't exist */ Tcl_DStringFree(&ds); break; } /* * File 'nativePath' does exist if we get here. We * now want to check if it is a symlink and otherwise * continue with the rest of the path. */ /* * Check for symlinks, except at last component * of path (we don't follow final symlinks). Also * a drive (C:/) for example, may sometimes have * the reparse flag set for some reason I don't * understand. We therefore don't perform this * check for drives. */ if (cur != 0 && !isDrive && (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { Tcl_Obj *to = WinReadLinkDirectory(nativePath); if (to != NULL) { /* Read the reparse point ok */ /* Tcl_GetStringFromObj(to, &pathLen); */ nextCheckpoint = 0; /* pathLen */ Tcl_AppendToObj(to, currentPathEndPosition, -1); /* Convert link to forward slashes */ for (path = Tcl_GetString(to); *path != 0; path++) { if (*path == '\\') *path = '/'; } path = Tcl_GetString(to); currentPathEndPosition = path + nextCheckpoint; if (temp != NULL) { Tcl_DecrRefCount(temp); } temp = to; /* Reset variables so we can restart normalization */ isDrive = 1; Tcl_DStringFree(&dsNorm); Tcl_DStringInit(&dsNorm); Tcl_DStringFree(&ds); continue; } } /* * Now we convert the tail of the current path to its * 'long form', and append it to 'dsNorm' which holds * the current normalized path */ if (isDrive) { WCHAR drive = ((WCHAR*)nativePath)[0]; if (drive >= L'a') { drive -= (L'a' - L'A'); ((WCHAR*)nativePath)[0] = drive; } Tcl_DStringAppend(&dsNorm,nativePath,Tcl_DStringLength(&ds)); } else { WIN32_FIND_DATAW fData; HANDLE handle; handle = FindFirstFileW((WCHAR*)nativePath, &fData); if (handle == INVALID_HANDLE_VALUE) { /* This is usually the '/' in 'c:/' at end of string */ Tcl_DStringAppend(&dsNorm,(CONST char*)L"/", sizeof(WCHAR)); } else { WCHAR *nativeName; if (fData.cFileName[0] != '\0') { nativeName = fData.cFileName; } else { nativeName = fData.cAlternateFileName; } FindClose(handle); Tcl_DStringAppend(&dsNorm,(CONST char*)L"/", sizeof(WCHAR)); Tcl_DStringAppend(&dsNorm,(TCHAR*)nativeName, wcslen(nativeName)*sizeof(WCHAR)); } } Tcl_DStringFree(&ds); lastValidPathEnd = currentPathEndPosition; if (cur == 0) { break; } /* * If we get here, we've got past one directory * delimiter, so we know it is no longer a drive */ isDrive = 0; } currentPathEndPosition++; } } /* Common code path for all Windows platforms */ nextCheckpoint = currentPathEndPosition - path; if (lastValidPathEnd != NULL) { /* * Concatenate the normalized string in dsNorm with the * tail of the path which we didn't recognise. The * string in dsNorm is in the native encoding, so we * have to convert it to Utf. */ Tcl_DString dsTemp; Tcl_WinTCharToUtf(Tcl_DStringValue(&dsNorm), Tcl_DStringLength(&dsNorm), &dsTemp); nextCheckpoint = Tcl_DStringLength(&dsTemp); if (*lastValidPathEnd != 0) { /* Not the end of the string */ int len; char *path; Tcl_Obj *tmpPathPtr; tmpPathPtr = Tcl_NewStringObj(Tcl_DStringValue(&dsTemp), nextCheckpoint); Tcl_AppendToObj(tmpPathPtr, lastValidPathEnd, -1); path = Tcl_GetStringFromObj(tmpPathPtr, &len); Tcl_SetStringObj(pathPtr, path, len); Tcl_DecrRefCount(tmpPathPtr); } else { /* End of string was reached above */ Tcl_SetStringObj(pathPtr, Tcl_DStringValue(&dsTemp), nextCheckpoint); } Tcl_DStringFree(&dsTemp); } Tcl_DStringFree(&dsNorm); return nextCheckpoint;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -