用Win32 API设置windows XP中FAT32文件夹共享的读写权限(二)
上篇中简单的说了下Windows XP中NTFS文件共享和FAT32文件共享的区别,在下半篇中我就不说废话了,直接将设置文件共享的读写权限的关键代码贴出来。
首先是将文件夹设为共享的代码:
NET_API_STATUS AddNetShare(LPSTR sharedFolderPath, LPSTR shareName)
{
DWORD level = 2;
SHARE_INFO_2 si;
DWORD parmErr = 0;
si.shi2_netname = shareName; //share name
si.shi2_type = STYPE_DISKTREE;
si.shi2_remark = (LPSTR)L"This is a shared folder."; //remark for the shared folder
si.shi2_path = sharedFolderPath; //path of the shared folder
si.shi2_permissions = ACCESS_ALL; //this parameter doesn't work acctually
si.shi2_passwd = NULL; //no password need
si.shi2_max_uses = -1; //unlimited connected
si.shi2_current_uses = 0;
NET_API_STATUS res = NetShareAdd(NULL, level, (LPBYTE)&si, &parmErr);
return res;
}
注意,在上篇中谈到过,SHARE_INFO_2中的shi2_permissions对于Windows XP无效,你可以设为任意值,但对文件夹的共享读写权限不起作用。
如果只调用上面的函数将文件夹设为共享,则默认情况下,网络用户拥有全部读写权限,但很多时候我们不希望网络用户修改共享文件的内容,这样就必须编程将共享权限设置为只读,下面就是设置共享权限的代码:
{
NetShareReadOnly = 0x001200a9, //readonly permission
NetShareFullControl = 0x001f01ff //full control permission
};
//Set access permission for net shared folder
DWORD SetNetsharePermission(LPTSTR shareName, NetShareAccessPermission permission)
{
DWORD res = 0;
PACL pOldDacl = NULL, pNewDacl = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS ea;
res = GetNamedSecurityInfo(shareName,
SE_LMSHARE,
DACL_SECURITY_INFORMATION ,
NULL,
NULL,
&pOldDacl,
NULL,
&pSD);
if (res != ERROR_SUCCESS)
{
goto Cleanup;
}
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = permission; //Set access permission (defined in enum NetShareAccessPermission)
ea.grfAccessMode = SET_ACCESS ;
ea.grfInheritance= CONTAINER_INHERIT_ACE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
ea.Trustee.ptstrName = L"Everyone";
res = SetEntriesInAcl(1, &ea, pOldDacl, &pNewDacl);
if (res != ERROR_SUCCESS)
{
goto Cleanup;
}
res = SetNamedSecurityInfo(shareName,
SE_LMSHARE,
DACL_SECURITY_INFORMATION ,
NULL,
NULL,
pNewDacl,
NULL);
Cleanup: //Release resource
if (pSD != NULL)
{
LocalFree((HLOCAL) pSD);
}
if (pNewDacl != NULL)
{
LocalFree((HLOCAL) pNewDacl);
}
return res;
}
这段代码最关键的语句是:
其中的permission参数是一个自定义的NetShareAccessPermission枚举,如果permission==NetShareReadOnly(即0x001200a9),这样就可以将共享文件夹设为只读了。
但问题的关键是为什么要自己定义一个这样的枚举?0x001200a9和0x001f01ff这两个密码一般的十六进制数是哪里来的?难道MSDN中没有定义一个这样的枚举或宏吗?
实际上,MSDN中的确存在几个预定义的可以为ea.grfAccessPermissions 赋值的宏,上面那两个十六进制数是一个与设置文件系统安全性有关的DWORD开关变量,名为ACCESS_MASK,具体定义可以参考MSDN。win32 API函数的头文件中已经定义了几个可以为这个参数赋值的宏,如GENERIC_READ,KEY_READ等,不过这两个宏在MSDN中也是语焉不详(还是我这个菜鸟实在菜到家了,人家明明说的清清楚楚,就你一个睁眼瞎……),但你可以在VS中输入这两个宏,然后选中后右键转入定义这两个东东的头文件,在头文件有少量的解释。在这个头文件中我们还可以看到更多的预定义的宏。
不幸的是,我没有找到我要的宏,KEY_READ是用来设置注册表只读权限的,GENERIC_READ,呃,我也不知道是用来设置什么的,只知道这两个宏对我的共享权限设置除了引发一些怪异的行为外,没什么帮助。
这样只能靠自己手动的设置那个恐怖的32位的开关变量了。对于一个32位的二进制数,一共有4G种组合,假设我试一种组合要花30s,将吃饭睡觉上XX的时间都搭上,一天24小时,算一下,呃,我要花3800年才试的完……
不过,我可以考虑将这项光荣的任务交给我未来的儿子,然后来个递归,利用“子又有子,子又有孙,子子孙孙无穷匮也,而const不可增”……
不过好在我思维还算缜密,我考虑到无法保证我会有儿子,这样我的递归很可能由于条件不满足产生异常而终止……
我一向不打无把握的仗,想到了一种投机取巧的办法:我可以先通过Windows的UI设置共享文件夹的权限,然后编程获取相关的变量和结构体的值,将这些值保存下来,先不管这些值看得懂看不懂(事实上,不太可能看得懂,又是一些32位的开关量,又是一些3800年),给我们的代码赋值就行了。
我没找到直接获取ACCESS_MASK的API,于是想办法通过VS的调试功能来获取,下面是我用来获取ACCESS_MASK的代码:
void GetAceTest()
{
DWORD res = 0;
PACL pOldDacl = NULL, pNewDacl = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS ea;
ACCESS_ALLOWED_ACE* pAce;
LPTSTR shareName=(LPTSTR)L"TestShareFolder";
res = GetNamedSecurityInfo(shareName,
SE_LMSHARE,
DACL_SECURITY_INFORMATION ,
NULL,
NULL,
&pOldDacl,
NULL,
&pSD);
GetAce(pOldDacl,0,(LPVOID*)&pAce);
ACCESS_MASK Mask=pAce->Mask;
return;
}
ACCESS_MASK是和ACE直接关联的,至于ACE么,呃,说来话长,还是看MSDN吧。
但要注意的是GetAce()的第二个参数要设为0,因为ACEs是从0开始索引的,如果不小心设为1了,你在VS调试器中看到的东西足够让你郁闷了。
另外,其实还有一个设置文件共享权限的方法。在上面将文件夹设为共享的代码中,将函数NetShareAdd()的第二个参数level设为502,第三个参数设为SHARE_INFO_2,如果将level设为502,第三个参数设为SHARE_INFO_502,就可以通过SHARE_INFO_502这个参数来设定权限了,其定义如下:
{
LPWSTR shi502_netname;
DWORD shi502_type;
LPWSTR shi502_remark;
DWORD shi502_permissions;
DWORD shi502_max_uses;
DWORD shi502_current_uses;
LPWSTR shi502_path;
LPWSTR shi502_passwd;
DWORD shi502_reserved;
PSECURITY_DESCRIPTOR shi502_security_descriptor;
} SHARE_INFO_502,
*PSHARE_INFO_502,
*LPSHARE_INFO_502;