用Win32 API设置windows XP中FAT32文件夹共享的读写权限(二)

     上篇中简单的说了下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参数就可以用来设置文件夹共享访问权限,但这个参数也是很难缠,我没有找到直接设置这个参数的方法,只能利用前面那种投机取巧的方法达到目的。

posted on 2008-08-09 19:50  wudong  阅读(5981)  评论(5编辑  收藏  举报

导航