Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenatom.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * COPYRIGHT: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ex/atom.c 00005 * PURPOSE: Executive Atom Functions 00006 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 00007 * Gunnar Dalsnes 00008 */ 00009 00010 /* INCLUDES *****************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 #define TAG_ATOM 'motA' 00017 00018 /* GLOBALS ****************************************************************/ 00019 00020 /* 00021 * FIXME: this is WRONG! The global atom table should live in the WinSta struct 00022 * and accessed through a win32k callout (received in PsEstablishWin32Callouts) 00023 * NOTE: There is a session/win32k global atom table also, but its private to 00024 * win32k. Its used for RegisterWindowMessage() and for window classes. 00025 * -Gunnar 00026 */ 00027 PRTL_ATOM_TABLE GlobalAtomTable; 00028 00029 /* PRIVATE FUNCTIONS *********************************************************/ 00030 00031 /*++ 00032 * @name ExpGetGlobalAtomTable 00033 * 00034 * Gets pointer to a global atom table, creates it if not already created 00035 * 00036 * @return Pointer to the RTL_ATOM_TABLE, or NULL if it's impossible 00037 * to create atom table 00038 * 00039 * @remarks Internal function 00040 * 00041 *--*/ 00042 PRTL_ATOM_TABLE 00043 NTAPI 00044 ExpGetGlobalAtomTable(VOID) 00045 { 00046 NTSTATUS Status; 00047 00048 /* Return it if we have one */ 00049 if (GlobalAtomTable) return GlobalAtomTable; 00050 00051 /* Create it */ 00052 Status = RtlCreateAtomTable(37, &GlobalAtomTable); 00053 00054 /* If we couldn't create it, return NULL */ 00055 if (!NT_SUCCESS(Status)) return NULL; 00056 00057 /* Return the newly created one */ 00058 return GlobalAtomTable; 00059 } 00060 00061 /* FUNCTIONS ****************************************************************/ 00062 00063 /*++ 00064 * @name NtAddAtom 00065 * @implemented 00066 * 00067 * Function NtAddAtom creates new Atom in Global Atom Table. If Atom 00068 * with the same name already exist, internal Atom counter is incremented. 00069 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtAddAtom.html 00070 * 00071 * @param AtomName 00072 * Atom name in Unicode 00073 * 00074 * @param AtomNameLength 00075 * Length of the atom name 00076 * 00077 * @param Atom 00078 * Pointer to RTL_ATOM 00079 * 00080 * @return STATUS_SUCCESS in case of success, proper error code 00081 * othwerwise. 00082 * 00083 * @remarks None 00084 * 00085 *--*/ 00086 NTSTATUS 00087 NTAPI 00088 NtAddAtom(IN PWSTR AtomName, 00089 IN ULONG AtomNameLength, 00090 OUT PRTL_ATOM Atom) 00091 { 00092 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); 00093 NTSTATUS Status; 00094 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00095 LPWSTR CapturedName; 00096 ULONG CapturedSize; 00097 RTL_ATOM SafeAtom; 00098 PAGED_CODE(); 00099 00100 /* Check for the table */ 00101 if (AtomTable == NULL) return STATUS_ACCESS_DENIED; 00102 00103 /* Check for valid name */ 00104 if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR))) 00105 { 00106 /* Fail */ 00107 DPRINT1("Atom name too long\n"); 00108 return STATUS_INVALID_PARAMETER; 00109 } 00110 00111 /* Re-use the given name if kernel mode or no atom name */ 00112 CapturedName = AtomName; 00113 00114 /* Check if we're called from user-mode*/ 00115 if (PreviousMode != KernelMode) 00116 { 00117 /* Enter SEH */ 00118 _SEH2_TRY 00119 { 00120 /* Check if we have a name */ 00121 if (AtomName) 00122 { 00123 /* Probe the atom */ 00124 ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR)); 00125 00126 /* Allocate an aligned buffer + the null char */ 00127 CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &~ 00128 (sizeof(WCHAR) -1)); 00129 CapturedName = ExAllocatePoolWithTag(PagedPool, 00130 CapturedSize, 00131 TAG_ATOM); 00132 if (!CapturedName) 00133 { 00134 /* Fail the call */ 00135 Status = STATUS_INSUFFICIENT_RESOURCES; 00136 } 00137 else 00138 { 00139 /* Copy the name and null-terminate it */ 00140 RtlCopyMemory(CapturedName, AtomName, AtomNameLength); 00141 CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL; 00142 } 00143 00144 /* Probe the atom too */ 00145 if (Atom) ProbeForWriteUshort(Atom); 00146 } 00147 } 00148 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00149 { 00150 /* Return the exception code */ 00151 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00152 } 00153 _SEH2_END; 00154 } 00155 00156 /* Call the runtime function */ 00157 Status = RtlAddAtomToAtomTable(AtomTable, CapturedName, &SafeAtom); 00158 if (NT_SUCCESS(Status) && (Atom)) 00159 { 00160 /* Success and caller wants the atom back.. .enter SEH */ 00161 _SEH2_TRY 00162 { 00163 /* Return the atom */ 00164 *Atom = SafeAtom; 00165 } 00166 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00167 { 00168 /* Get the exception code */ 00169 Status = _SEH2_GetExceptionCode(); 00170 } 00171 _SEH2_END; 00172 } 00173 00174 /* If we captured anything, free it */ 00175 if ((CapturedName) && (CapturedName != AtomName)) 00176 ExFreePoolWithTag(CapturedName, TAG_ATOM); 00177 00178 /* Return to caller */ 00179 return Status; 00180 } 00181 00182 /*++ 00183 * @name NtDeleteAtom 00184 * @implemented 00185 * 00186 * Removes Atom from Global Atom Table. If Atom's reference counter 00187 * is greater then 1, function decrements this counter, but Atom 00188 * stayed in Global Atom Table. 00189 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtDeleteAtom.html 00190 * 00191 * @param Atom 00192 * Atom identifier 00193 * 00194 * @return STATUS_SUCCESS in case of success, proper error code 00195 * othwerwise. 00196 * 00197 * @remarks None 00198 * 00199 *--*/ 00200 NTSTATUS 00201 NTAPI 00202 NtDeleteAtom(IN RTL_ATOM Atom) 00203 { 00204 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); 00205 PAGED_CODE(); 00206 00207 /* Check for valid table */ 00208 if (AtomTable == NULL) return STATUS_ACCESS_DENIED; 00209 00210 /* Call worker function */ 00211 return RtlDeleteAtomFromAtomTable(AtomTable, Atom); 00212 } 00213 00214 /*++ 00215 * @name NtFindAtom 00216 * @implemented 00217 * 00218 * Retrieves existing Atom's identifier without incrementing Atom's 00219 * internal counter 00220 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtFindAtom.html 00221 * 00222 * @param AtomName 00223 * Atom name in Unicode 00224 * 00225 * @param AtomNameLength 00226 * Length of the atom name 00227 * 00228 * @param Atom 00229 * Pointer to RTL_ATOM 00230 * 00231 * @return STATUS_SUCCESS in case of success, proper error code 00232 * othwerwise. 00233 * 00234 * @remarks None 00235 * 00236 *--*/ 00237 NTSTATUS 00238 NTAPI 00239 NtFindAtom(IN PWSTR AtomName, 00240 IN ULONG AtomNameLength, 00241 OUT PRTL_ATOM Atom) 00242 { 00243 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); 00244 NTSTATUS Status; 00245 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00246 LPWSTR CapturedName = NULL; 00247 ULONG CapturedSize; 00248 RTL_ATOM SafeAtom; 00249 PAGED_CODE(); 00250 00251 /* Check for the table */ 00252 if (AtomTable == NULL) return STATUS_ACCESS_DENIED; 00253 00254 /* Check for valid name */ 00255 if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR))) 00256 { 00257 /* Fail */ 00258 DPRINT1("Atom name too long\n"); 00259 return STATUS_INVALID_PARAMETER; 00260 } 00261 00262 /* Re-use the given name if kernel mode or no atom name */ 00263 CapturedName = AtomName; 00264 00265 /* Check if we're called from user-mode*/ 00266 if (PreviousMode != KernelMode) 00267 { 00268 /* Enter SEH */ 00269 _SEH2_TRY 00270 { 00271 /* Check if we have a name */ 00272 if (AtomName) 00273 { 00274 /* Probe the atom */ 00275 ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR)); 00276 00277 /* Allocate an aligned buffer + the null char */ 00278 CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &~ 00279 (sizeof(WCHAR) -1)); 00280 CapturedName = ExAllocatePoolWithTag(PagedPool, 00281 CapturedSize, 00282 TAG_ATOM); 00283 if (!CapturedName) 00284 { 00285 /* Fail the call */ 00286 Status = STATUS_INSUFFICIENT_RESOURCES; 00287 } 00288 else 00289 { 00290 /* Copy the name and null-terminate it */ 00291 RtlCopyMemory(CapturedName, AtomName, AtomNameLength); 00292 CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL; 00293 } 00294 00295 /* Probe the atom too */ 00296 if (Atom) ProbeForWriteUshort(Atom); 00297 } 00298 } 00299 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00300 { 00301 /* Return the exception code */ 00302 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00303 } 00304 _SEH2_END; 00305 } 00306 00307 /* Call the runtime function */ 00308 Status = RtlLookupAtomInAtomTable(AtomTable, CapturedName, &SafeAtom); 00309 if (NT_SUCCESS(Status) && (Atom)) 00310 { 00311 /* Success and caller wants the atom back.. .enter SEH */ 00312 _SEH2_TRY 00313 { 00314 /* Return the atom */ 00315 *Atom = SafeAtom; 00316 } 00317 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00318 { 00319 Status = _SEH2_GetExceptionCode(); 00320 } 00321 _SEH2_END; 00322 } 00323 00324 /* If we captured anything, free it */ 00325 if ((CapturedName) && (CapturedName != AtomName)) 00326 ExFreePoolWithTag(CapturedName, TAG_ATOM); 00327 00328 /* Return to caller */ 00329 return Status; 00330 } 00331 00332 /*++ 00333 * @name NtQueryInformationAtom 00334 * @implemented 00335 * 00336 * Gets single Atom properties or reads Global Atom Table 00337 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtQueryInformationAtom.html 00338 * 00339 * @param Atom 00340 * Atom to query. If AtomInformationClass parameter is 00341 * AtomTableInformation, Atom parameter is not used. 00342 * 00343 * @param AtomInformationClass 00344 * See ATOM_INFORMATION_CLASS enumeration type for details 00345 * 00346 * @param AtomInformation 00347 * Result of call - pointer to user's allocated buffer for data 00348 * 00349 * @param AtomInformationLength 00350 * Size of AtomInformation buffer, in bytes 00351 * 00352 * @param ReturnLength 00353 * Pointer to ULONG value containing required AtomInformation 00354 * buffer size 00355 * 00356 * @return STATUS_SUCCESS in case of success, proper error code 00357 * othwerwise. 00358 * 00359 * @remarks None 00360 * 00361 *--*/ 00362 NTSTATUS 00363 NTAPI 00364 NtQueryInformationAtom(RTL_ATOM Atom, 00365 ATOM_INFORMATION_CLASS AtomInformationClass, 00366 PVOID AtomInformation, 00367 ULONG AtomInformationLength, 00368 PULONG ReturnLength) 00369 { 00370 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); 00371 PATOM_BASIC_INFORMATION BasicInformation = AtomInformation; 00372 PATOM_TABLE_INFORMATION TableInformation = AtomInformation; 00373 NTSTATUS Status = STATUS_SUCCESS; 00374 ULONG Flags, UsageCount, NameLength, RequiredLength = 0; 00375 KPROCESSOR_MODE PreviousMode; 00376 00377 PAGED_CODE(); 00378 00379 /* Check for valid table */ 00380 if (AtomTable == NULL) return STATUS_ACCESS_DENIED; 00381 00382 PreviousMode = ExGetPreviousMode(); 00383 00384 _SEH2_TRY 00385 { 00386 /* Probe the parameters */ 00387 if (PreviousMode != KernelMode) 00388 { 00389 ProbeForWrite(AtomInformation, 00390 AtomInformationLength, 00391 sizeof(ULONG)); 00392 00393 if (ReturnLength != NULL) 00394 { 00395 ProbeForWriteUlong(ReturnLength); 00396 } 00397 } 00398 00399 /* Choose class */ 00400 switch (AtomInformationClass) 00401 { 00402 /* Caller requested info about an atom */ 00403 case AtomBasicInformation: 00404 00405 /* Size check */ 00406 RequiredLength = FIELD_OFFSET(ATOM_BASIC_INFORMATION, Name); 00407 if (RequiredLength > AtomInformationLength) 00408 { 00409 /* Fail */ 00410 DPRINT1("Buffer too small\n"); 00411 Status = STATUS_INFO_LENGTH_MISMATCH; 00412 _SEH2_LEAVE; 00413 } 00414 00415 /* Prepare query */ 00416 UsageCount = 0; 00417 NameLength = AtomInformationLength - RequiredLength; 00418 BasicInformation->Name[0] = UNICODE_NULL; 00419 00420 /* Query the data */ 00421 Status = RtlQueryAtomInAtomTable(AtomTable, 00422 Atom, 00423 &UsageCount, 00424 &Flags, 00425 BasicInformation->Name, 00426 &NameLength); 00427 if (NT_SUCCESS(Status)) 00428 { 00429 /* Return data */ 00430 BasicInformation->UsageCount = (USHORT)UsageCount; 00431 BasicInformation->Flags = (USHORT)Flags; 00432 BasicInformation->NameLength = (USHORT)NameLength; 00433 RequiredLength += NameLength + sizeof(WCHAR); 00434 } 00435 break; 00436 00437 /* Caller requested info about an Atom Table */ 00438 case AtomTableInformation: 00439 00440 /* Size check */ 00441 RequiredLength = FIELD_OFFSET(ATOM_TABLE_INFORMATION, Atoms); 00442 if (RequiredLength > AtomInformationLength) 00443 { 00444 /* Fail */ 00445 DPRINT1("Buffer too small\n"); 00446 Status = STATUS_INFO_LENGTH_MISMATCH; 00447 _SEH2_LEAVE; 00448 } 00449 00450 /* Query the data */ 00451 Status = RtlQueryAtomListInAtomTable(AtomTable, 00452 (AtomInformationLength - RequiredLength) / 00453 sizeof(RTL_ATOM), 00454 &TableInformation->NumberOfAtoms, 00455 TableInformation->Atoms); 00456 if (NT_SUCCESS(Status)) 00457 { 00458 /* Update the return length */ 00459 RequiredLength += TableInformation->NumberOfAtoms * sizeof(RTL_ATOM); 00460 } 00461 break; 00462 00463 /* Caller was on crack */ 00464 default: 00465 00466 /* Unrecognized class */ 00467 Status = STATUS_INVALID_INFO_CLASS; 00468 break; 00469 } 00470 00471 /* Return the required size */ 00472 if (ReturnLength != NULL) 00473 { 00474 *ReturnLength = RequiredLength; 00475 } 00476 } 00477 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00478 { 00479 Status = _SEH2_GetExceptionCode(); 00480 } 00481 _SEH2_END; 00482 00483 /* Return to caller */ 00484 return Status; 00485 } 00486 00487 /* EOF */ Generated on Sun May 27 2012 04:24:24 for ReactOS by
1.7.6.1
|