2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
16 #include <afs/afs_consts.h>
34 #include <afs/opr_assert.h>
36 #include <WINNT\afsreg.h>
39 fs_ExtractDriveLetter(char *inPathp, char *outPathp)
41 if (inPathp[0] != 0 && inPathp[1] == ':') {
42 /* there is a drive letter */
43 *outPathp++ = *inPathp++;
44 *outPathp++ = *inPathp++;
53 /* strip the drive letter from a component */
55 fs_StripDriveLetter(char *inPathp, char *outPathp, size_t outSize)
57 char tempBuffer[1000];
59 if( FAILED(StringCbCopy(tempBuffer, sizeof(tempBuffer), inPathp))) {
60 fprintf (stderr, "fs_StripDriveLetter - not enough space on input");
63 if (tempBuffer[0] != 0 && tempBuffer[1] == ':') {
64 /* drive letter present */
65 if( FAILED(StringCbCopy(outPathp, outSize, tempBuffer+2))) {
66 fprintf (stderr, "fs_StripDriveLetter - not enough space on output");
71 /* no drive letter present */
72 if( FAILED(StringCbCopy(outPathp, outSize, tempBuffer))) {
73 fprintf (stderr, "fs_StripDriveLetter - not enough space on output");
80 /* take a path with a drive letter, possibly relative, and return a full path
81 * without the drive letter. This is the full path relative to the working
82 * dir for that drive letter. The input and output paths can be the same.
85 fs_GetFullPath(char *pathp, char *outPathp, size_t outSize)
95 if (pathp[0] != 0 && pathp[1] == ':') {
96 /* there's a drive letter there */
104 if (*firstp == '\\' || *firstp == '/') {
105 /* already an absolute pathname, just copy it back */
106 if( FAILED(StringCbCopy(outPathp, outSize, firstp))) {
107 fprintf (stderr, "fs_GetFullPath - not enough space on output");
113 GetCurrentDirectoryA(sizeof(origPath), origPath);
116 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
117 /* a drive has been specified and it isn't our current drive.
118 * to get path, switch to it first. Must case-fold drive letters
119 * for user convenience.
125 if (!SetCurrentDirectoryA(newPath)) {
126 code = GetLastError();
131 /* now get the absolute path to the current wdir in this drive */
132 GetCurrentDirectoryA(sizeof(tpath), tpath);
133 if( FAILED(StringCbCopy(outPathp, outSize, tpath+2))) {
134 fprintf (stderr, "fs_GetFullPath - not enough space on output");
137 /* if there is a non-null name after the drive, append it */
139 if( FAILED(StringCbCat(outPathp, outSize, "\\"))) {
140 fprintf (stderr, "fs_GetFullPath - not enough space on output");
143 if( FAILED(StringCbCat(outPathp, outSize, firstp))) {
144 fprintf (stderr, "fs_GetFullPath - not enough space on output");
149 /* finally, if necessary, switch back to our home drive letter */
151 SetCurrentDirectoryA(origPath);
157 /* is this a digit or a digit-like thing? */
158 static int ismeta(int abase, int ac) {
159 /* if (ac == '-' || ac == 'x' || ac == 'X') return 1; */
160 if (ac >= '0' && ac <= '7') return 1;
161 if (abase <= 8) return 0;
162 if (ac >= '8' && ac <= '9') return 1;
163 if (abase <= 10) return 0;
164 if (ac >= 'a' && ac <= 'f') return 1;
165 if (ac >= 'A' && ac <= 'F') return 1;
169 /* given that this is a digit or a digit-like thing, compute its value */
170 static int getmeta(int ac) {
171 if (ac >= '0' && ac <= '9') return ac - '0';
172 if (ac >= 'a' && ac <= 'f') return ac - 'a' + 10;
173 if (ac >= 'A' && ac <= 'F') return ac - 'A' + 10;
177 char *cm_mount_root="afs";
178 char *cm_slash_mount_root="/afs";
179 char *cm_back_slash_mount_root="\\afs";
182 fs_utils_InitMountRoot()
185 char mountRoot[MAX_PATH+1];
186 char *pmount=mountRoot;
187 DWORD len=sizeof(mountRoot)-1;
189 if ((RegOpenKeyExA(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
190 (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey)!= ERROR_SUCCESS)
191 || (RegQueryValueExA(parmKey, "Mountroot", NULL, NULL,(LPBYTE)(mountRoot), &len)!= ERROR_SUCCESS)
192 || (len==sizeof(mountRoot)-1)
195 if( FAILED(StringCbCopy(mountRoot, sizeof(mountRoot), "\\afs"))) {
196 fprintf (stderr, "fs_InitMountRoot - not enough space on output");
200 RegCloseKey(parmKey);
201 mountRoot[len]=0; /*safety see ms-help://MS.MSDNQTR.2002OCT.1033/sysinfo/base/regqueryvalueex.htm*/
203 cm_mount_root=malloc(len+1);
204 cm_slash_mount_root=malloc(len+2);
205 cm_back_slash_mount_root=malloc(len+2);
206 if ((*pmount=='/') || (*pmount='\\'))
209 if( FAILED(StringCbCopy(cm_mount_root, len+1, pmount))) {
210 fprintf (stderr, "fs_InitMountRoot - not enough space on output");
213 cm_slash_mount_root[0]='/';
214 if( FAILED(StringCbCopy(cm_slash_mount_root+1, len+1, pmount))) {
215 fprintf (stderr, "fs_InitMountRoot - not enough space on output");
218 cm_back_slash_mount_root[0]='\\';
219 if( FAILED(StringCbCopy(cm_back_slash_mount_root+1, len+1, pmount))) {
220 fprintf (stderr, "fs_InitMountRoot - not enough space on output");
225 /* return a static pointer to a buffer */
227 fs_GetParent(char *apath)
229 static char tspace[1024];
232 if( FAILED(StringCbCopy(tspace, sizeof(tspace), apath))) {
233 fprintf (stderr, "tspace - not enough space");
236 tp = strrchr(tspace, '\\');
238 if (tp - tspace > 2 &&
241 *(tp+1) = 0; /* lv trailing slash so Parent("k:\foo") is "k:\" not "k:" */
246 fs_ExtractDriveLetter(apath, tspace);
247 if( FAILED(StringCbCat(tspace, sizeof(tspace), "."))) {
248 fprintf (stderr, "tspace - not enough space");
255 #if (_WINNT_WIN32 < 0x0600)
256 typedef struct FILE_NAME_INFO {
257 DWORD FileNameLength;
259 } FILE_NAME_INFO, *PFILE_NAME_INFO;
261 typedef enum _FILE_INFO_BY_HANDLE_CLASS {
263 } FILE_INFO_BY_HANDLE_CLASS, *PFILE_INFO_BY_HANDLE_CLASS;
267 LPFN_GetFileInformationByHandleEx)(
269 __in FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
270 __out LPVOID lpFileInformation,
271 __in DWORD dwBufferSize
276 GetFileSystemNameInfo(const char *fileNamep, char *outNamep, size_t outSize)
280 FILE_NAME_INFO nameInfo;
284 #if (_WIN32_WINNT < 0x0600)
286 static LPFN_GetFileInformationByHandleEx GetFileInformationByHandleEx = NULL;
288 if (!GetFileInformationByHandleEx) {
289 hKernel32 = GetModuleHandle("kernel32.dll"); /* no refcount increase */
290 GetFileInformationByHandleEx = (LPFN_GetFileInformationByHandleEx)GetProcAddress(hKernel32, "GetFileInformationByHandleEx");
294 if (!GetFileInformationByHandleEx)
297 hf = CreateFile( fileNamep,
299 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
302 FILE_FLAG_BACKUP_SEMANTICS,
305 if (hf == INVALID_HANDLE_VALUE)
308 rc = GetFileInformationByHandleEx( hf, FileNameInfo, &u, sizeof(u));
313 rc = WideCharToMultiByte(CP_UTF8, 0,
314 u.nameInfo.FileName, u.nameInfo.FileNameLength,
317 if (rc == 0) /* failure */
320 if (outNamep[0] == '\\' &&
321 outNamep[u.nameInfo.FileNameLength/2 - 1] == '\\')
322 outNamep[u.nameInfo.FileNameLength/2 - 1] = 0;
324 outNamep[min(u.nameInfo.FileNameLength/2, outSize)] = 0; /* make sure we are nul terminated */
329 /* this function returns TRUE (1) if the file is in AFS, otherwise false (0) */
331 fs_InAFS(char *apath)
333 char fsname[MAX_PATH+2]="\\";
334 struct ViceIoctl blob;
335 cm_ioctlQueryOptions_t options;
340 * If the operating system supports the name information query
341 * use it to resolve the full file path. This will take care
342 * of any mappings, ntfs junctions, etc.
344 if (GetFileSystemNameInfo(apath, &fsname[1], sizeof(fsname)-1) == 0)
347 memset(&options, 0, sizeof(options));
348 options.size = sizeof(options);
349 options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
351 blob.in_size = options.size; /* no variable length data */
353 blob.out_size = sizeof(cm_fid_t);
354 blob.out = (char *) &fid;
356 code = pioctl_utf8(apath, VIOCGETFID, &blob, 1);
358 if ((errno == EINVAL) || (errno == ENOENT))
365 fs_IsFreelanceRoot(char *apath)
367 struct ViceIoctl blob;
369 char space[AFS_PIOCTL_MAXSIZE];
372 blob.out_size = AFS_PIOCTL_MAXSIZE;
375 code = pioctl_utf8(apath, VIOC_FILE_CELL_NAME, &blob, 1);
377 return !cm_strnicmp_utf8N("Freelance.Local.Root",space, blob.out_size);
379 return 1; /* assume it is because it is more restrictive that way */
385 static char buffer[NETBIOSNAMESZ] = "AFS";
391 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
392 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
393 if (code == ERROR_SUCCESS) {
394 dummyLen = sizeof(buffer);
395 code = RegQueryValueEx(parmKey, "NetbiosName", NULL, NULL,
397 RegCloseKey (parmKey);
399 if( FAILED(StringCbCopy(buffer, sizeof(buffer), "AFS"))) {
400 fprintf (stderr, "buffer - not enough space");
407 #define AFSCLIENT_ADMIN_GROUPNAME "AFS Client Admins"
412 static BOOL fAdmin = FALSE;
413 static BOOL fTested = FALSE;
417 /* Obtain the SID for the AFS client admin group. If the group does
418 * not exist, then assume we have AFS client admin privileges.
420 PSID psidAdmin = NULL;
421 DWORD dwSize, dwSize2;
422 char pszAdminGroup[ MAX_COMPUTERNAME_LENGTH + sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2 ];
423 char *pszRefDomain = NULL;
424 SID_NAME_USE snu = SidTypeGroup;
426 dwSize = sizeof(pszAdminGroup);
428 if (!GetComputerName(pszAdminGroup, &dwSize)) {
429 /* Can't get computer name. We return false in this case.
430 Retain fAdmin and fTested. This shouldn't happen.*/
437 if( FAILED(StringCbCat(pszAdminGroup, MAX_COMPUTERNAME_LENGTH + sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2,"\\"))) {
438 fprintf (stderr, "pszAdminGroup - not enough space");
441 if( FAILED(StringCbCat(pszAdminGroup, MAX_COMPUTERNAME_LENGTH +
442 sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2, AFSCLIENT_ADMIN_GROUPNAME))) {
443 fprintf (stderr, "pszAdminGroup - not enough space");
447 LookupAccountName(NULL, pszAdminGroup, NULL, &dwSize, NULL, &dwSize2, &snu);
448 /* that should always fail. */
450 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
451 /* if we can't find the group, then we allow the operation */
456 if (dwSize == 0 || dwSize2 == 0) {
462 psidAdmin = (PSID)malloc(dwSize); memset(psidAdmin,0,dwSize);
464 pszRefDomain = (char *)malloc(dwSize2);
465 assert(pszRefDomain);
467 if (!LookupAccountName(NULL, pszAdminGroup, psidAdmin, &dwSize, pszRefDomain, &dwSize2, &snu)) {
468 /* We can't lookup the group now even though we looked it up earlier.
469 Could this happen? */
472 /* Then open our current ProcessToken */
475 if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
478 if (!CheckTokenMembership(hToken, psidAdmin, &fAdmin)) {
479 /* We'll have to allocate a chunk of memory to store the list of
480 * groups to which this user belongs; find out how much memory
484 PTOKEN_GROUPS pGroups;
486 GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &dwSize);
488 pGroups = (PTOKEN_GROUPS)malloc(dwSize);
491 /* Allocate that buffer, and read in the list of groups. */
492 if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &dwSize))
494 /* Look through the list of group SIDs and see if any of them
495 * matches the AFS Client Admin group SID.
498 for (; (!fAdmin) && (iGroup < pGroups->GroupCount); ++iGroup)
500 if (EqualSid (psidAdmin, pGroups->Groups[ iGroup ].Sid)) {
510 /* if do not have permission because we were not explicitly listed
511 * in the Admin Client Group let's see if we are the SYSTEM account
514 PTOKEN_USER pTokenUser;
515 SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
516 PSID pSidLocalSystem = 0;
519 GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);
521 pTokenUser = (PTOKEN_USER)malloc(dwSize);
524 if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
525 gle = GetLastError();
527 if (AllocateAndInitializeSid( &SIDAuth, 1,
528 SECURITY_LOCAL_SYSTEM_RID,
532 if (EqualSid(pTokenUser->User.Sid, pSidLocalSystem)) {
536 FreeSid(pSidLocalSystem);
555 fs_FreeUtf8CmdLine(int argc, char ** argv)
558 for (i=0; i < argc; i++) {
566 fs_MakeUtf8Cmdline(int argc, const wchar_t **wargv)
571 argv = calloc(argc, sizeof(argv[0]));
575 for (i=0; i < argc; i++) {
578 s = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL, FALSE);
580 (argv[i] = calloc(s+1, sizeof(char))) == NULL) {
584 s = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], s+1, NULL, FALSE);
591 fs_FreeUtf8CmdLine(argc, argv);
598 static const char *pn = "<cmd>";
600 fs_SetProcessName(const char *name)
606 fs_Die(int code, char *filename)
608 if (code == EINVAL) {
610 fprintf(stderr,"%s: Invalid argument; it is possible that %s is not in AFS.\n", pn, filename);
612 fprintf(stderr,"%s: Invalid argument.\n", pn);
614 else if (code == ENOENT) {
616 fprintf(stderr,"%s: File '%s' doesn't exist\n", pn, filename);
618 fprintf(stderr,"%s: no such file returned\n", pn);
620 else if (code == EEXIST) {
622 fprintf(stderr,"%s: File '%s' already exists.\n", pn, filename);
624 fprintf(stderr,"%s: the specified file already exists.\n", pn);
626 else if (code == EROFS)
627 fprintf(stderr,"%s: You can not change a backup or readonly volume\n", pn);
628 else if (code == EACCES || code == EPERM) {
630 fprintf(stderr,"%s: You don't have the required access rights on '%s'\n", pn, filename);
632 fprintf(stderr,"%s: You do not have the required rights to do this operation\n", pn);
634 else if (code == ENODEV) {
635 fprintf(stderr,"%s: AFS service may not have started.\n", pn);
637 else if (code == ESRCH) { /* hack */
638 fprintf(stderr,"%s: Cell name not recognized.\n", pn);
640 else if (code == EPIPE) { /* hack */
641 fprintf(stderr,"%s: Volume name or ID not recognized.\n", pn);
643 else if (code == EFBIG) {
644 fprintf(stderr,"%s: Cache size too large.\n", pn);
646 else if (code == ETIMEDOUT) {
648 fprintf(stderr,"%s:'%s': Connection timed out", pn, filename);
650 fprintf(stderr,"%s: Connection timed out", pn);
652 else if (code == EBUSY) {
654 fprintf(stderr,"%s: All servers are busy on which '%s' resides\n", pn, filename);
656 fprintf(stderr,"%s: All servers are busy\n", pn);
658 else if (code == ENXIO) {
660 fprintf(stderr,"%s: All volume instances are offline on which '%s' resides\n", pn, filename);
662 fprintf(stderr,"%s: All volume instances are offline\n", pn);
664 else if (code == ENOSYS) {
666 fprintf(stderr,"%s: All servers are down on which '%s' resides\n", pn, filename);
668 fprintf(stderr,"%s: All servers are down\n", pn);
670 else if (code == ECHILD) { /* hack */
672 fprintf(stderr,"%s: Invalid owner specified for '%s'\n", pn, filename);
674 fprintf(stderr,"%s: Invalid owner specified\n", pn);
678 fprintf(stderr,"%s:'%s'", pn, filename);
680 fprintf(stderr,"%s", pn);
682 fprintf(stderr, ": code 0x%x\n", code);
686 /* values match cache manager File Types */
688 fs_filetypestr(afs_uint32 type)