Рассылка закрыта
При закрытии подписчики были переданы в рассылку "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 |
Отписаться
Убрать рекламу |
| В избранное | ||
