上篇中簡單的說了下Windows XP中NTFS檔案分享權限設定和FAT32檔案分享權限設定的區別,在下半篇中我就不說廢話了,直接將設定檔案分享權限設定的讀寫權限的關鍵代碼貼出來。
首先是將檔案夾設為共用程式碼:
//Set a folder for net share
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無效,你可以設為任意值,但對檔案夾的共用讀寫權限不起作用。
如果只調用上面的函數將檔案夾設為共用,則預設情況下,網路使用者擁有全部讀寫權限,但很多時候我們不希望網路使用者修改共用檔案的內容,這樣就必須編程將共用使用權限設定為唯讀,下面就是設定共用許可權的代碼:
enum NetShareAccessPermission
{
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;
}
這段代碼最關鍵的語句是:
ea.grfAccessPermissions = permission;
其中的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的代碼:
//Get the value of 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這個參數來設定許可權了,其定義如下:
typedef struct _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;
其中的PSECURITY_DESCRIPTOR shi502_security_descriptor參數就可以用來設定檔案夾共用存取權限,但這個參數也是很難纏,我沒有找到直接設定這個參數的方法,只能利用前面那種投機取巧的方法達到目的。