Рассылка закрыта
При закрытии подписчики были переданы в рассылку "Delphi - проблемы и решения" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
← Август 2002 → | ||||||
1
|
2
|
3
|
4
|
|||
---|---|---|---|---|---|---|
5
|
7
|
8
|
9
|
10
|
11
|
|
12
|
13
|
14
|
15
|
16
|
17
|
18
|
19
|
21
|
22
|
23
|
24
|
25
|
|
26
|
27
|
28
|
29
|
30
|
31
|
Автор
Статистика
6.267 подписчиков
-22 за неделю
-22 за неделю
NTFS : Управление квотами (часть I)
Информационный Канал Subscribe.Ru |
Выпуск номер : 4 [ 30 июля 2002 года]
Здравствуйте, уважаемые подписчики.
Сначала хочу напомнить еще не подписавшимся получателям пробных выпусков рассылки : это последний пробный выпуск и если вы хотите подписаться на эту рассылку, то сделайте это прямо сейчас (форма для подписки должна быть вверху).
Этот выпуск немного уменьшенный (хотел написать больше). Это связано с тем, что в конце письма находится мой вариант перевода заголовочного файла dskquota.h на Pascal. Хотел его выложить на сайте, но там сейчас технические трудности. Если вы обнаружите в нем ошибки, то пожалуйста напишите мне flint@vtc.ru.
И еще - все, кто писал мне (примерно с конца позапрошлой недели) и не получил ответа, повторите пожалуйста ваше письмо (а то были технические проблемы) на flint@vtc.ru.
Сегодня в рассылке:
- Файловые системы в Windows NT
- dskquota.pas
Статья
Файловые системы в Windows NT
В Windows NT в основном используются файловые системы FAT (FAT16 и с Win2000 FAT32) и NTFS. Просто перечислю несколько достоинств и недостатков каждой.
FAT16 самая универсальная файловая система - она поддерживается DOS и всеми известными Windows. Платой за универсальность является - низкая эффективность (размер кластера для диска размером 1024Mb равен 32Kb), максимальный размер тома ограничен 4Гб и ограничение на кол-во файлов, находящихся в корне диска (максимум 256).
FAT32 лишена многих недостатков FAT16 : максимальный размер в Windows 2000 - 32Гб (теоретически - до 8 терабайт), размер кластера для диска в 1024Mb - 4Kb и нет ограничения на кол-во файлов в корне диска + она хранит вторую копию загрузочного сектора. Но она не будет работать в старых версиях DOS :)) и в Windows NT 4 и ниже (Хотя существуют драйвера FAT32 для NT4 и при чем неплохо работают, но загрузить с FAT32 NT4 не удастся.
NTFS - родная для NT файловая система. Максимальный размер тома - 128 терабайт (я даже не знаю, проверяли ли это на практике :). Размер кластера по умолчанию меньше, чем в FAT32 - 1Kb для диска в 1024Mb (хотя это некоторым не нравится ;-). Но в NTFS есть ряд дополнительных возможностей - ограничение доступа к файлам, сжатие файлов, индексация фалов, полная поддержка Unicode, поддержка POSIX (ну это так, к слову). Также в NTFS5 (Win2000 и далее) поддерживаются следующие возможности - шифрование, отслеживание ссылок, разряженные файлы, поддержка дефрагментации, жесткие ссылки, точки соединения, переназначение плохих секторов, множественные потоки данных и квоты на размер дискового пространства. В этом и нескольких следующих выпусках мы разберем, как работать с этими возможностями. А пока начнем с квот.
Квоты позволяют вам ограничивать размер дискового пространства для определенных пользователей. При этом возможно при превышении квоты запретить пользователю записывать на диск (здесь и далее под словом диск имеется в виду логический диск (раздел)). Использование квот возможно только на Win2000 и далее. Хотя есть решение (а возможно даже не одно) и для NT4, но оно от сторонних разработчиков, несколько кривовато и легко обходится. Но здесь будет описываться именно квоты в NTFS5.
Управлять квотами можно с помощью закладки Квота в свойствах диска. Но видна эта закладка будет только администраторам, и вообще квотами могут управлять только они.
Для управления квотами используется COM-объект и COM-интерфейсы : IDiskQuotaControl, IDiskQuotaUser и еще 3 штуки. Работе с COM я учить не буду (меня самого можно этому учить :) - по этой теме можно найти много материала. И еще - чтобы не вдаваться в подробности интерфейса(внешнего вида) программы представьте, что бы пишем эту самую закладку Квоты. И еще маленькое дополнение - в C++ все COM-интерфейсы описаны в файле dskquota.h . Аналогичного файла для Delphi я не нашел - пришлось перевести все руками. Найти мой вариант можно в конце рассылки (буду очень рад, если укажите на допущенные в нем ошибки).
В uses добавляем dskquota{это мой файл},ComObj,ActiveX;
Quota : IDiskQuotaControl; // COM-интерфейс - сделаем его глобальной переменной
При открытии нашей закладки выполняем инициализацию COM.
var Res : HRESULT; Res:=CoCreateInstance(CLSID_DiskQuotaControl,nil, CLSCTX_INPROC_SERVER,IDiskQuotaControl,Quota); if FAILED(Res) then ShowMessage('Error in CoCreateInstance');
В общем, каждая функция интерфейсов возвращает результат своего выполнения. Проверить его можно, например, функцией FAILED(), возвращающей TRUE в случае ошибки. Так как такие проверки занимают огромное место, то я их здесь приводить не буду.
Теперь нам надо инициализировать объект и сопоставить ему диск. Например, диск E: Quota.Initialize('e:\',true);
Теперь любые операции с Quota будут выполняться с диском e:. true во втором параметре обозначает полный доступ. И еще - все строки только Unicode!!! т.е. типа PWideChar, а не PChar.
Теперь нам надо расставить все данные о состоянии.Сначала получим эти данные -
var State : Cardinal; Quota.GetQuotaState(State); В State теперь находится информация о состоянии. "Включить управление квотами" = not DiskQuotaIsDisabled(State);Данная строка показывает, что галочка напротив "Включить управление квотами" должна появится если результат функции DiskQuotaIsDisabled будет равен FALSE. Функция DiskQuotaIsDisabled есть в dskquota.pas
"Не выделять место на диске при превышении квоты" = DiskQuotaIsEnforced(State);
Теперь получим "квоты по умолчанию для нового пользователя этого тома".
var Limit : Int64; Quota.GetDefaultQuotaLimit(Limit); if Limit=-1 //т.е. квота на ограничена then "Не ограничивать выделение места на диске" else begin "Выделять на диске не более" := Format('%g',[Limit/1024]); //килобайт. Quota.GetDefaultQuotaThreshold(Limit); "Порог выдачи предупреждений":= Format('%g',[Limit/1024]); //килобайт. end;Если нам надо получить эти значения в тексте, например, "243 Mb" или "не ограничено", то воспользуемся соответственно GetDefaultQuotaLimitText и GetDefaultQuotaThresholdText. Пример,
var LimitTxt : array[0..255] of WideChar; Quota.GetDefaultQuotaLimitText(LimitTxt,255); LimitText.Caption:=LimitTxt;И еще остались два checkbox'а в "Протоколирование превышения квоты для этого тома".
var LogState : Cardinal;
Quota.GetQuotaLogFlags(LogState);
"Регистрация превышения квоты пользователем":=DiskQuotaIsLoggedUserLimit(LogState);
"Регистрация превышения порога предупреждения":=DiskQuotaIsLoggedUserThreshold(LogState);
Все это красиво организовывается в функцию, например, GetQuotaInfo. Про SetQuotaInfo чуть позже, а пока коротко о некоторых вопросах :
Выключенная "Не выделять место на диске при превышении квоты" означает то, что пользователь может записывать больше положенного. При включенной опции и попытке перерасхода квоты юзер получает сообщение "Нет места на диске". При чем при расчете занятого места используется номинальный размер, а не фактический (т.е. 10 мегабайтный файл, сжатый (средствами NTFS) до 5Mb при расчете квоты будет считаться как 10 мегабайтный).
Квота по умолчанию применяется к пользователям, первый раз записавшим данные на диск.
Результаты протоколирования будут в журнале системы (eventvwr.exe). Например, такие:
Источник : ntfs Категория : диск Пользователь : COMPUTER\User Пользователь достиг предела по квоте на томе E:
Обратная операция - устанавливаем измененные данные.
var State,LogState : Cardinal; Res : HRESULT; Limit : Int64; begin State:=0; if not "Включить управление квотами" then DiskQuotaSetDisabled(State) else begin if "Не выделять место на диске при превышении квоты" then DiskQuotaSetEnforced(State) else DiskQuotaSetTracked(State); end; Res:=Quota.SetQuotaState(State); if FAILED(Res) then ShowMessage('FAILED'); if "Не ограничивать выделение места на диске" then Limit:=-1 else Limit:=StrToInt(LimitSize.Text)*1024; // т.к. у нас в килобайтах Quota.SetDefaultQuotaLimit(Limit); //"Порог выдачи предупреждений" //устанавливается Quota.SetDefaultQuotaThreshold() DiskQuotaSetLogUserTreshold(LogState,CheckBox2.Checked); DiskQuotaSetLogUserLimit(LogState,CheckBox1.Checked); Quota.SetQuotaLogFlags(LogState); end;
Продолжение будет в следующем выпуске.
Заголовочный файл dskquota.pas
Перевод файла dskquota.h из VC7 на Pascal
unit dskquota; interface uses Windows,ActiveX; const CLSID_DiskQuotaControl : TGUID = '{7988B571-EC89-11cf-9C00-00AA00A14F56}'; type LONGLONG = int64; ULONG = Cardinal; // // Definitions for value and bits in DWORD returned by // IDiskQuotaControl::GetQuotaState. // const DISKQUOTA_STATE_DISABLED = $00000000; DISKQUOTA_STATE_TRACK = $00000001; DISKQUOTA_STATE_ENFORCE = $00000002; DISKQUOTA_STATE_MASK = $00000003; DISKQUOTA_FILESTATE_INCOMPLETE = $00000100; DISKQUOTA_FILESTATE_REBUILDING = $00000200; DISKQUOTA_FILESTATE_MASK = $00000300; // // Definitions for bits in DWORD returned by // IDiskQuotaControl::GetQuotaLogFlags. // const DISKQUOTA_LOGFLAG_USER_THRESHOLD = $00000001; DISKQUOTA_LOGFLAG_USER_LIMIT = $00000002; // // Values for fNameResolution argument to: // // IDiskQuotaControl::AddUserSid // IDiskQuotaControl::AddUserName // IDiskQuotaControl::FindUserSid // IDiskQuotaControl::CreateEnumUsers // DISKQUOTA_USERNAME_RESOLVE_NONE = 0; DISKQUOTA_USERNAME_RESOLVE_SYNC = 1; DISKQUOTA_USERNAME_RESOLVE_ASYNC = 2; // // Values for status returned by IDiskQuotaUser::GetAccountStatus. // DISKQUOTA_USER_ACCOUNT_RESOLVED = 0; DISKQUOTA_USER_ACCOUNT_UNAVAILABLE = 1; DISKQUOTA_USER_ACCOUNT_DELETED = 2; DISKQUOTA_USER_ACCOUNT_INVALID = 3; DISKQUOTA_USER_ACCOUNT_UNKNOWN = 4; DISKQUOTA_USER_ACCOUNT_UNRESOLVED = 5; type TDiskQuotaUserInformation = record QuotaUsed : LONGLONG; QuotaThreshold : LONGLONG; QuotaLimit : LONGLONG; end; PDISKQUOTA_USER_INFORMATION = ^PDISKQUOTA_USER_INFORMATION; DISKQUOTA_USER_INFORMATION = TDiskQuotaUserInformation; // // IDiskQuotaUser represents a single user quota record on a particular // NTFS volume. Objects using this interface are instantiated // through several IDiskQuotaControl methods. // type PPDiskQuotaUser = ^PDiskQuotaUser; PDiskQuotaUser = ^IDiskQuotaUser; IDiskQuotaUser = interface ['{7988B574-EC89-11cf-9C00-00AA00A14F56}'] function GetID(var pulID : ULONG):HRESULT;stdcall; function GetName( pszAccountContainer : PWideChar; cchAccountContainer : DWORD; pszLogonName : PWideChar; cchLogonName : DWORD; pszDisplayName : LPWSTR; cchDisplayName : DWORD):HRESULT;stdcall; function GetSidLength(var pdwLength : DWORD):HRESULT; function GetSid ( bSidBuffer : Pointer; cbSidBuffer : DWORD):HRESULT;stdcall; function GetQuotaThreshold ( var pllThreshold : LONGLONG):HRESULT;stdcall; function GetQuotaThresholdText ( pszText : LPWSTR; cchText : DWORD):HRESULT;stdcall; function GetQuotaLimit ( var pllLimit : LONGLONG):HRESULT;stdcall; function GetQuotaLimitText ( pszText : LPWSTR; cchText : DWORD):HRESULT;stdcall; function GetQuotaUsed ( var pllUsed : LONGLONG):HRESULT;stdcall; function GetQuotaUsedText ( pszText : LPWSTR; cchText : DWORD):HRESULT;stdcall; function GetQuotaInformation ( pbQuotaInfo : Pointer; cbQuotaInfo : DWORD):HRESULT;stdcall; function SetQuotaThreshold ( llThreshold : LONGLONG; fWriteThrough : BOOL):HRESULT;stdcall; function SetQuotaLimit ( llLimit : LONGLONG; fWriteThrough : BOOL):HRESULT;stdcall; function Invalidate():HRESULT;stdcall; function GetAccountStatus ( var pdwStatus : DWORD):HRESULT;stdcall; end; // // IEnumDiskQuotaUsers represents an enumerator created by // IDiskQuotaControl for the purpose of enumerating individual user quota // records on a particular volume. Each record is represented through // the IDiskQuotaUser interface. // type PPEnumDiskQuotaUsers = ^PEnumDiskQuotaUsers; PEnumDiskQuotaUsers = ^IEnumDiskQuotaUsers; IEnumDiskQuotaUsers = interface(IUnknown) ['{7988B577-EC89-11cf-9C00-00AA00A14F56}'] function Next( cUsers : DWORD; rgUsers : PPDiskQuotaUser; var pcUsersFetched : DWORD):HRESULT;stdcall; function Skip(cUsers : DWORD):HRESULT;stdcall; function Reset():HRESULT;stdcall; function Clone(ppEnum : PPEnumDiskQuotaUsers):HRESULT;stdcall; end; // // IDiskQuotaUserBatch represents a collection of IDiskQuotaUser // pointers for the purpose of grouping updates to quota information. // type PPDiskQuotaUserBatch = ^PDiskQuotaUserBatch; PDiskQuotaUserBatch = ^IDiskQuotaUserBatch; IDiskQuotaUserBatch = interface ['{7988B576-EC89-11cf-9C00-00AA00A14F56}'] function Add (pUser : PDiskQuotaUser):HRESULT;stdcall; function Remove (pUser : PDiskQuotaUser):HRESULT;stdcall; function RemoveAll ():HRESULT;stdcall; function FlushToDisk ():HRESULT;stdcall; end; // // IDiskQuotaControl represents a disk volume, providing query and // control of that volume's quota information. // type PDiskQuotaControl = ^IDiskQuotaControl; IDiskQuotaControl = interface (IConnectionPointContainer) ['{7988B572-EC89-11cf-9C00-00AA00A14F56}'] function Initialize ( pszPath : LPWSTR; bReadWrite : LongBOOL):HRESULT;stdcall; function SetQuotaState (dwState : DWORD):HRESULT;stdcall; function GetQuotaState (var pdwState : DWORD):HRESULT;stdcall; function SetQuotaLogFlags (dwFlags : DWORD):HRESULT;stdcall; function GetQuotaLogFlags (var pdwFlags : DWORD):HRESULT;stdcall; function SetDefaultQuotaThreshold (llThreshold : LONGLONG):HRESULT;stdcall; function GetDefaultQuotaThreshold (var pllThreshold : LONGLONG):HRESULT;stdcall; function GetDefaultQuotaThresholdText ( pszText : LPWSTR; cchText : DWORD):HRESULT;stdcall; function SetDefaultQuotaLimit(llLimit : LONGLONG):HRESULT;stdcall; function GetDefaultQuotaLimit (var pllLimit : LONGLONG):HRESULT;stdcall; function GetDefaultQuotaLimitText( pszText : LPWSTR; cchText : DWORD):HRESULT;stdcall; function AddUserSid ( pUserSid : PSID; fNameResolution : DWORD; var ppUser : PDiskQuotaUser):HRESULT;stdcall; function AddUserName ( pszLogonName : LPCWSTR; fNameResolution : DWORD; var ppUser : PDiskQuotaUser):HRESULT;stdcall; function DeleteUser ( ppUser : PDiskQuotaUser):HRESULT;stdcall; function FindUserSid ( pUserSid : PSID; fNameResolution :DWORD; var ppUser : PDiskQuotaUser):HRESULT;stdcall; function FindUserName ( pszLogonName : LPCWSTR; var ppUser : PDiskQuotaUser):HRESULT;stdcall; function CreateEnumUsers ( rgpUserSids : Pointer; cpSids : DWORD; fNameResolution : DWORD; ppEnum : PPEnumDiskQuotaUsers):HRESULT;stdcall; { function CreateEnumUsers ( rgpUserSids : Pointer; cpSids : DWORD; fNameResolution : DWORD; var ppEnum : PEnumDiskQuotaUsers):HRESULT;stdcall; } function CreateUserBatch ({var} ppBatch : PPDiskQuotaUserBatch):HRESULT;stdcall; function InvalidateSidNameCache ():HRESULT;stdcall; function GiveUserNameResolutionPriority (pUser : PDiskQuotaUser):HRESULT;stdcall; function ShutdownNameResolution ():HRESULT;stdcall; end; //typedef IDiskQuotaControl DISKQUOTA_CONTROL, *PDISKQUOTA_CONTROL; type IDiskQuotaEvents = interface ['{7988B579-EC89-11cf-9C00-00AA00A14F56}'] function OnUserNameChanged(pUser : PDiskQuotaUser):HRESULT;stdcall; end; procedure DiskQuotaSetDisabled(var S:Cardinal); procedure DiskQuotaSetTracked(var S:Cardinal); procedure DiskQuotaSetEnforced(var S:Cardinal); function DiskQuotaIsDisabled(S:Cardinal):Boolean; function DiskQuotaIsTracked(S:Cardinal):Boolean; function DiskQuotaIsEnforced(S:Cardinal):Boolean; function DiskQuotaFileIncomplete(S:Cardinal):Boolean; function DiskQuotaFileRebuilding(S:Cardinal):Boolean; function DiskQuotaIsLoggedUserThreshold(f:Cardinal):Boolean; function DiskQuotaIsLoggedUserLimit(f:Cardinal):Boolean; procedure DiskQuotaSetLogUserTreshold(var f : Cardinal; yn:Boolean); procedure DiskQuotaSetLogUserLimit(var f:Cardinal; yn:Boolean); implementation // // Helper macros for setting and testing state value. // procedure DiskQuotaSetDisabled(var S:Cardinal); begin S:=S and not DISKQUOTA_STATE_MASK; end; procedure DiskQuotaSetTracked(var S:Cardinal); begin S := S or (DISKQUOTA_STATE_MASK and DISKQUOTA_STATE_TRACK); end; procedure DiskQuotaSetEnforced(var S:Cardinal); begin S := S or (DISKQUOTA_STATE_ENFORCE and DISKQUOTA_STATE_ENFORCE ); end; function DiskQuotaIsDisabled(S:Cardinal):Boolean; begin Result:=(DISKQUOTA_STATE_DISABLED=(S and DISKQUOTA_STATE_MASK)); end; function DiskQuotaIsTracked(S:Cardinal):Boolean; begin Result:=(DISKQUOTA_STATE_TRACK = (S and DISKQUOTA_STATE_MASK)); end; function DiskQuotaIsEnforced(S:Cardinal):Boolean; begin Result:= (DISKQUOTA_STATE_ENFORCE = (S and DISKQUOTA_STATE_MASK)); end; // // These file state flags are read-only. // function DiskQuotaFileIncomplete(S:Cardinal):Boolean; begin Result:= ((S and DISKQUOTA_FILESTATE_INCOMPLETE)<>0); end; function DiskQuotaFileRebuilding(S:Cardinal):Boolean; begin Result:= ((S and DISKQUOTA_FILESTATE_REBUILDING)<>0); end; // // Helper macros to interrogate a log flags DWORD. // function DiskQuotaIsLoggedUserThreshold(f:Cardinal):Boolean; begin Result:=((F and DISKQUOTA_LOGFLAG_USER_THRESHOLD)<>0); end; function DiskQuotaIsLoggedUserLimit(f:Cardinal):Boolean; begin Result:= (F and DISKQUOTA_LOGFLAG_USER_LIMIT)<>0; end; // // Helper macros to set/clear bits in a log flags DWORD. // procedure DiskQuotaSetLogUserTreshold(var f : Cardinal; yn:Boolean); begin F := F and not DISKQUOTA_LOGFLAG_USER_THRESHOLD; if yn then F := F or DISKQUOTA_LOGFLAG_USER_THRESHOLD; end; procedure DiskQuotaSetLogUserLimit(var f:Cardinal; yn:Boolean); begin F := F and not DISKQUOTA_LOGFLAG_USER_LIMIT; if yn then F := F or DISKQUOTA_LOGFLAG_USER_LIMIT; end; end.
Вот и все на сегодня.
С уважением, ведущий рассылки FliNT
http://subscribe.ru/
E-mail: ask@subscribe.ru |
Отписаться
Убрать рекламу |
В избранное | ||