1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592 |
- /*++
- Copyright (c) 2013 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- fileio.c
- Abstract:
- This module implements file I/O routines.
- Author:
- Evan Green 5-Mar-2013
- Environment:
- User Mode C Library
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "libcp.h"
- #include <alloca.h>
- #include <assert.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <paths.h>
- #include <poll.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <unistd.h>
- #include <limits.h>
- //
- // --------------------------------------------------------------------- Macros
- //
- #define ASSERT_POLL_FLAGS_EQUIVALENT() \
- ASSERT((POLLIN == POLL_EVENT_IN) && \
- (POLLRDBAND == POLL_EVENT_IN_HIGH_PRIORITY) && \
- (POLLOUT == POLL_EVENT_OUT) && \
- (POLLWRBAND == POLL_EVENT_OUT_HIGH_PRIORITY) && \
- (POLLERR == POLL_EVENT_ERROR) && \
- (POLLHUP == POLL_EVENT_DISCONNECTED) && \
- (POLLNVAL == POLL_EVENT_INVALID_HANDLE))
- //
- // Figure this out on 64 bits, as pollfd needs to have an int for a descriptor,
- // but the kernel wants pointer sized descriptors.
- //
- #define ASSERT_POLL_STRUCTURE_EQUIVALENT() \
- ASSERT(sizeof(struct pollfd) == sizeof(POLL_DESCRIPTOR))
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the initial size for the terminal name buffer.
- //
- #define INITIAL_TERMINAL_NAME_BUFFER_SIZE 64
- //
- // Define the initial allocation size for the asprintf destination string.
- //
- #define ASPRINT_INITIAL_BUFFER_SIZE 64
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure defines the context used during the asprintf/vasprintf
- routines.
- Members:
- Buffer - Stores a pointer to the allocated string buffer.
- Size - Stores the number of valid characters currently in the buffer.
- Capacity - Stores the maximum number of bytes that can fit in the buffer
- before it will need to be reallocated.
- --*/
- typedef struct _ASPRINT_CONTEXT {
- PSTR Buffer;
- UINTN Size;
- UINTN Capacity;
- } ASPRINT_CONTEXT, *PASPRINT_CONTEXT;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- int
- ClpOpen (
- int Directory,
- const char *Path,
- int OpenFlags,
- va_list ArgumentList
- );
- BOOL
- ClpAsPrintWriteCharacter (
- INT Character,
- PPRINT_FORMAT_CONTEXT Context
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Store a pointer to the global buffer used by the ttyname function.
- //
- PSTR ClTerminalNameBuffer;
- size_t ClTerminalNameBufferSize;
- //
- // Store a pointer to the global buffer used by the ctermid function.
- //
- PSTR ClTerminalIdBuffer;
- //
- // ------------------------------------------------------------------ Functions
- //
- LIBC_API
- int
- open (
- const char *Path,
- int OpenFlags,
- ...
- )
- /*++
- Routine Description:
- This routine opens a file and connects it to a file descriptor.
- Arguments:
- Path - Supplies a pointer to a null terminated string containing the path
- of the file to open.
- OpenFlags - Supplies a set of flags ORed together. See O_* definitions.
- ... - Supplies an optional integer representing the permission mask to set
- if the file is to be created by this open call.
- Return Value:
- Returns a file descriptor on success.
- -1 on failure. The errno variable will be set to indicate the error.
- --*/
- {
- va_list ArgumentList;
- int Result;
- va_start(ArgumentList, OpenFlags);
- Result = ClpOpen(AT_FDCWD, Path, OpenFlags, ArgumentList);
- va_end(ArgumentList);
- return Result;
- }
- LIBC_API
- int
- openat (
- int Directory,
- const char *Path,
- int OpenFlags,
- ...
- )
- /*++
- Routine Description:
- This routine opens a file and connects it to a file descriptor.
- Arguments:
- Directory - Supplies an optional file descriptor. If the given path
- is a relative path, the directory referenced by this descriptor will
- be used as a starting point for path resolution. Supply AT_FDCWD to
- use the working directory for relative paths.
- Path - Supplies a pointer to a null terminated string containing the path
- of the file to open.
- OpenFlags - Supplies a set of flags ORed together. See O_* definitions.
- ... - Supplies an optional integer representing the permission mask to set
- if the file is to be created by this open call.
- Return Value:
- Returns a file descriptor on success.
- -1 on failure. The errno variable will be set to indicate the error.
- --*/
- {
- va_list ArgumentList;
- int Result;
- va_start(ArgumentList, OpenFlags);
- Result = ClpOpen(Directory, Path, OpenFlags, ArgumentList);
- va_end(ArgumentList);
- return Result;
- }
- LIBC_API
- int
- fcntl (
- int FileDescriptor,
- int Command,
- ...
- )
- /*++
- Routine Description:
- This routine performs a file control operation on an open file handle.
- Arguments:
- FileDescriptor - Supplies the file descriptor to operate on.
- Command - Supplies the file control command. See F_* definitions.
- ... - Supplies any additional command-specific arguments.
- Return Value:
- Returns some value other than -1 to indicate success. For some commands
- (like F_DUPFD) this is a file descriptor. For others (like F_GETFD and
- F_GETFL) this is a bitfield of status flags.
- -1 on error, and errno will be set to indicate the error.
- --*/
- {
- va_list ArgumentList;
- off_t CurrentOffset;
- int DescriptorMinimum;
- FILE_CONTROL_COMMAND FileControlCommand;
- struct flock *FileLock;
- ULONG Flags;
- off_t Length;
- FILE_CONTROL_PARAMETERS_UNION Parameters;
- int ReturnValue;
- int SetFlags;
- struct stat Stat;
- KSTATUS Status;
- ReturnValue = -1;
- FileControlCommand = FileControlCommandInvalid;
- FileLock = NULL;
- va_start(ArgumentList, Command);
- switch (Command) {
- case F_DUPFD:
- FileControlCommand = FileControlCommandDuplicate;
- DescriptorMinimum = va_arg(ArgumentList, int);
- if (DescriptorMinimum < 0) {
- Status = STATUS_INVALID_PARAMETER;
- goto fcntlEnd;
- }
- Parameters.DuplicateDescriptor = (HANDLE)(UINTN)DescriptorMinimum;
- break;
- case F_GETFD:
- FileControlCommand = FileControlCommandGetFlags;
- Parameters.Flags = 0;
- break;
- case F_SETFD:
- FileControlCommand = FileControlCommandSetFlags;
- Parameters.Flags = 0;
- SetFlags = va_arg(ArgumentList, int);
- if ((SetFlags & FD_CLOEXEC) != 0) {
- Parameters.Flags |= FILE_DESCRIPTOR_CLOSE_ON_EXECUTE;
- }
- break;
- case F_GETFL:
- FileControlCommand = FileControlCommandGetStatusAndAccess;
- Parameters.Flags = 0;
- break;
- case F_SETFL:
- FileControlCommand = FileControlCommandSetStatus;
- Parameters.Flags = 0;
- //
- // Only a few flags are honored by the kernel. Changing access mode
- // for instance is not possible.
- //
- SetFlags = va_arg(ArgumentList, int);
- if ((SetFlags & O_APPEND) != 0) {
- Parameters.Flags |= SYS_OPEN_FLAG_APPEND;
- }
- if ((SetFlags & O_NONBLOCK) != 0) {
- Parameters.Flags |= SYS_OPEN_FLAG_NON_BLOCKING;
- }
- if ((SetFlags & O_NOATIME) != 0) {
- Parameters.Flags |= SYS_OPEN_FLAG_NO_ACCESS_TIME;
- }
- if ((SetFlags & O_ASYNC) != 0) {
- Parameters.Flags |= SYS_OPEN_FLAG_ASYNCHRONOUS;
- }
- break;
- case F_GETOWN:
- FileControlCommand = FileControlCommandGetSignalOwner;
- Parameters.Owner = 0;
- break;
- case F_SETOWN:
- FileControlCommand = FileControlCommandSetSignalOwner;
- Parameters.Owner = va_arg(ArgumentList, pid_t);
- break;
- case F_GETLK:
- case F_SETLK:
- case F_SETLKW:
- if (Command == F_GETLK) {
- FileControlCommand = FileControlCommandGetLock;
- } else if (Command == F_SETLK) {
- FileControlCommand = FileControlCommandSetLock;
- } else {
- assert(Command == F_SETLKW);
- FileControlCommand = FileControlCommandBlockingSetLock;
- }
- //
- // Convert the flock structure to a file lock. Start with the type.
- //
- FileLock = va_arg(ArgumentList, struct flock *);
- switch (FileLock->l_type) {
- case F_RDLCK:
- Parameters.FileLock.Type = FileLockRead;
- break;
- case F_WRLCK:
- Parameters.FileLock.Type = FileLockReadWrite;
- break;
- case F_UNLCK:
- Parameters.FileLock.Type = FileLockUnlock;
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- goto fcntlEnd;
- }
- //
- // Make the offset relative to the beginning of the file.
- //
- Parameters.FileLock.Offset = FileLock->l_start;
- switch (FileLock->l_whence) {
- case SEEK_SET:
- break;
- case SEEK_CUR:
- CurrentOffset = lseek(FileDescriptor, 0, SEEK_CUR);
- if (CurrentOffset == -1) {
- Status = STATUS_INVALID_PARAMETER;
- goto fcntlEnd;
- }
- Parameters.FileLock.Offset += CurrentOffset;
- break;
- case SEEK_END:
- if (fstat(FileDescriptor, &Stat) != 0) {
- Status = STATUS_INVALID_PARAMETER;
- goto fcntlEnd;
- }
- Parameters.FileLock.Offset += Stat.st_size;
- break;
- }
- //
- // Get the length sorted out, which may be negative.
- //
- Length = FileLock->l_len;
- if (Length < 0) {
- if (Parameters.FileLock.Offset < (ULONGLONG)Length) {
- Length = Parameters.FileLock.Offset;
- }
- Parameters.FileLock.Offset -= Length;
- Length = -Length;
- }
- Parameters.FileLock.Size = Length;
- Parameters.FileLock.ProcessId = 0;
- break;
- case F_CLOSEM:
- FileControlCommand = FileControlCommandCloseFrom;
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- goto fcntlEnd;
- }
- Status = OsFileControl((HANDLE)(UINTN)FileDescriptor,
- FileControlCommand,
- &Parameters);
- if (!KSUCCESS(Status)) {
- //
- // The kernel returns access denied if the open handle permissions
- // aren't correct, which this routine converts to invalid handle.
- // The kernel also returns resource in use, which this routine
- // converts to try again.
- //
- if ((Command == F_GETLK) || (Command == F_SETLK) ||
- (Command == F_SETLKW)) {
- if (Status == STATUS_ACCESS_DENIED) {
- Status = STATUS_INVALID_HANDLE;
- } else if (Status == STATUS_RESOURCE_IN_USE) {
- Status = STATUS_TRY_AGAIN;
- }
- }
- goto fcntlEnd;
- }
- switch (Command) {
- case F_DUPFD:
- ReturnValue = (int)(UINTN)(Parameters.DuplicateDescriptor);
- break;
- case F_GETFD:
- ReturnValue = 0;
- if ((Parameters.Flags & FILE_DESCRIPTOR_CLOSE_ON_EXECUTE) != 0) {
- ReturnValue |= FD_CLOEXEC;
- }
- break;
- case F_SETFD:
- case F_SETFL:
- case F_CLOSEM:
- ReturnValue = 0;
- break;
- case F_GETFL:
- ReturnValue = 0;
- Flags = Parameters.Flags;
- if ((Flags & SYS_OPEN_FLAG_READ) != 0) {
- ReturnValue |= O_RDONLY;
- }
- if ((Flags & SYS_OPEN_FLAG_WRITE) != 0) {
- ReturnValue |= O_WRONLY;
- }
- if ((Flags & SYS_OPEN_FLAG_EXECUTE) != 0) {
- ReturnValue |= O_EXEC;
- }
- if ((Flags & SYS_OPEN_FLAG_TRUNCATE) != 0) {
- ReturnValue |= O_TRUNC;
- }
- if ((Flags & SYS_OPEN_FLAG_APPEND) != 0) {
- ReturnValue |= O_APPEND;
- }
- if ((Flags & SYS_OPEN_FLAG_NON_BLOCKING) != 0) {
- ReturnValue |= O_NONBLOCK;
- }
- if ((Flags & SYS_OPEN_FLAG_CREATE) != 0) {
- ReturnValue |= O_CREAT;
- }
- if ((Flags & SYS_OPEN_FLAG_FAIL_IF_EXISTS) != 0) {
- ReturnValue |= O_EXCL;
- }
- if ((Flags & SYS_OPEN_FLAG_DIRECTORY) != 0) {
- ReturnValue |= O_DIRECTORY;
- }
- if ((Flags & SYS_OPEN_FLAG_NO_SYMBOLIC_LINK) != 0) {
- ReturnValue |= O_NOFOLLOW;
- }
- if ((Flags & SYS_OPEN_FLAG_SYNCHRONIZED) != 0) {
- ReturnValue |= O_SYNC;
- }
- if ((Flags & SYS_OPEN_FLAG_NO_CONTROLLING_TERMINAL) != 0) {
- ReturnValue |= O_NOCTTY;
- }
- if ((Flags & SYS_OPEN_FLAG_NO_ACCESS_TIME) != 0) {
- ReturnValue |= O_NOATIME;
- }
- if ((Flags & SYS_OPEN_FLAG_ASYNCHRONOUS) != 0) {
- ReturnValue |= O_ASYNC;
- }
- break;
- case F_GETLK:
- case F_SETLK:
- case F_SETLKW:
- //
- // Convert back to an flock structure.
- //
- switch (Parameters.FileLock.Type) {
- case FileLockRead:
- FileLock->l_type = F_RDLCK;
- break;
- case FileLockReadWrite:
- FileLock->l_type = F_WRLCK;
- break;
- //
- // If unlocked, don't convert any other parameters. F_GETLK is
- // supposed to return EINVAL if no valid locking information was
- // returned.
- //
- case FileLockUnlock:
- FileLock->l_type = F_UNLCK;
- if (Command == F_GETLK) {
- Status = STATUS_INVALID_PARAMETER;
- }
- ReturnValue = 0;
- goto fcntlEnd;
- default:
- assert(FALSE);
- Status = STATUS_INVALID_PARAMETER;
- goto fcntlEnd;
- }
- FileLock->l_start = Parameters.FileLock.Offset;
- FileLock->l_len = Parameters.FileLock.Size;
- FileLock->l_pid = Parameters.FileLock.ProcessId;
- FileLock->l_whence = SEEK_SET;
- ReturnValue = 0;
- break;
- case F_GETOWN:
- ReturnValue = Parameters.Owner;
- break;
- case F_SETOWN:
- ReturnValue = 0;
- break;
- default:
- assert(FALSE);
- goto fcntlEnd;
- }
- fcntlEnd:
- va_end(ArgumentList);
- if (!KSUCCESS(Status)) {
- ReturnValue = -1;
- errno = ClConvertKstatusToErrorNumber(Status);
- }
- return ReturnValue;
- }
- LIBC_API
- int
- close (
- int FileDescriptor
- )
- /*++
- Routine Description:
- This routine closes a file descriptor.
- Arguments:
- FileDescriptor - Supplies the file descriptor to close.
- Return Value:
- 0 on success.
- -1 if the file could not be closed properly. The state of the file
- descriptor is undefined, but in many cases is still open. The errno
- variable will be set to contain more detailed information.
- --*/
- {
- KSTATUS Status;
- Status = OsClose((HANDLE)(UINTN)FileDescriptor);
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- return 0;
- }
- LIBC_API
- int
- closefrom (
- int FileDescriptor
- )
- /*++
- Routine Description:
- This routine closes all file descriptors with a value greater than or
- equal to the given file descriptor.
- Arguments:
- FileDescriptor - Supplies the minimum file descriptor number.
- Return Value:
- 0 on success.
- -1 if a file descriptor could not be closed properly. The state of the file
- descriptor is undefined, but in many cases is still open. The errno
- variable will be set to contain more detailed information.
- --*/
- {
- return fcntl(FileDescriptor, F_CLOSEM);
- }
- LIBC_API
- ssize_t
- read (
- int FileDescriptor,
- void *Buffer,
- size_t ByteCount
- )
- /*++
- Routine Description:
- This routine attempts to read the specifed number of bytes from the given
- open file descriptor.
- Arguments:
- FileDescriptor - Supplies the file descriptor returned by the open function.
- Buffer - Supplies a pointer to the buffer where the read bytes will be
- returned.
- ByteCount - Supplies the number of bytes to read.
- Return Value:
- Returns the number of bytes successfully read from the file.
- -1 on failure, and errno will contain more information.
- --*/
- {
- UINTN BytesCompleted;
- KSTATUS Status;
- //
- // Truncate the byte count, so that it does not exceed the maximum number
- // of bytes that can be returned.
- //
- if (ByteCount > (size_t)SSIZE_MAX) {
- ByteCount = (size_t)SSIZE_MAX;
- }
- //
- // Ask the OS to actually do the I/O.
- //
- Status = OsPerformIo((HANDLE)(UINTN)FileDescriptor,
- IO_OFFSET_NONE,
- ByteCount,
- 0,
- SYS_WAIT_TIME_INDEFINITE,
- (PVOID)Buffer,
- &BytesCompleted);
- if (Status == STATUS_TIMEOUT) {
- errno = EAGAIN;
- return -1;
- } else if ((!KSUCCESS(Status)) && (Status != STATUS_END_OF_FILE)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- if (BytesCompleted == 0) {
- BytesCompleted = -1;
- }
- }
- return (ssize_t)BytesCompleted;
- }
- LIBC_API
- ssize_t
- pread (
- int FileDescriptor,
- void *Buffer,
- size_t ByteCount,
- off_t Offset
- )
- /*++
- Routine Description:
- This routine attempts to read the specifed number of bytes from the given
- open file descriptor at a given offset. It does not change the current
- file pointer.
- Arguments:
- FileDescriptor - Supplies the file descriptor returned by the open function.
- Buffer - Supplies a pointer to the buffer where the read bytes will be
- returned.
- ByteCount - Supplies the number of bytes to read.
- Offset - Supplies the offset from the start of the file to read from.
- Return Value:
- Returns the number of bytes successfully read from the file.
- -1 on failure, and errno will contain more information.
- --*/
- {
- UINTN BytesCompleted;
- KSTATUS Status;
- //
- // Truncate the byte count, so that it does not exceed the maximum number
- // of bytes that can be returned.
- //
- if (ByteCount > (size_t)SSIZE_MAX) {
- ByteCount = (size_t)SSIZE_MAX;
- }
- //
- // Ask the OS to actually do the I/O.
- //
- Status = OsPerformIo((HANDLE)(UINTN)FileDescriptor,
- Offset,
- ByteCount,
- 0,
- SYS_WAIT_TIME_INDEFINITE,
- (PVOID)Buffer,
- &BytesCompleted);
- if (Status == STATUS_TIMEOUT) {
- errno = EAGAIN;
- return -1;
- } else if ((!KSUCCESS(Status)) && (Status != STATUS_END_OF_FILE)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- if (BytesCompleted == 0) {
- BytesCompleted = -1;
- }
- }
- return (ssize_t)BytesCompleted;
- }
- LIBC_API
- int
- rename (
- const char *SourcePath,
- const char *DestinationPath
- )
- /*++
- Routine Description:
- This routine attempts to rename the object at the given path. This routine
- operates on symbolic links themselves, not the destinations of symbolic
- links. If the source and destination paths are equal, this routine will do
- nothing and return successfully. If the source path is not a directory, the
- destination path must not be a directory. If the destination file exists,
- it will be deleted. The caller must have write access in both the old and
- new directories. If the source path is a directory, the destination path
- must not exist or be an empty directory. The destination path must not have
- a path prefix of the source (ie it's illegal to move /my/path into
- /my/path/stuff).
- Arguments:
- SourcePath - Supplies a pointer to a null terminated string containing the
- name of the file or directory to rename.
- DestinationPath - Supplies a pointer to a null terminated string
- containing the path to rename the file or directory to. This path
- cannot span file systems.
- Return Value:
- 0 on success.
- -1 on failure, and the errno variable will be set to contain more
- information.
- --*/
- {
- return renameat(AT_FDCWD, SourcePath, AT_FDCWD, DestinationPath);
- }
- LIBC_API
- int
- renameat (
- int SourceDirectory,
- const char *SourcePath,
- int DestinationDirectory,
- const char *DestinationPath
- )
- /*++
- Routine Description:
- This routine operates the same as the rename function, except it allows
- relative source and/or destination paths to begin from a directory
- specified by the given file descriptors.
- Arguments:
- SourceDirectory - Supplies a file descriptor to the directory to start
- source path searches from. If the source path is absolute, this value
- is ignored. If this is AT_FDCWD, then source path searches will
- start from the current working directory.
- SourcePath - Supplies a pointer to a null terminated string containing the
- name of the file or directory to rename.
- DestinationPath - Supplies a pointer to a null terminated string
- containing the path to rename the file or directory to. This path
- cannot span file systems.
- DestinationDirectory - Supplies an optional file descriptor to the
- directory to start destination path searches from. If the destination
- path is absolute, this value is ignored. If this is AT_FDCWD, then
- destination path searches will start from the current working directory.
- Return Value:
- 0 on success.
- -1 on failure, and the errno variable will be set to contain more
- information.
- --*/
- {
- KSTATUS Status;
- if ((SourcePath == NULL) || (DestinationPath == NULL)) {
- errno = EINVAL;
- return -1;
- }
- Status = OsRename((HANDLE)(UINTN)SourceDirectory,
- (PSTR)SourcePath,
- strlen(SourcePath) + 1,
- (HANDLE)(UINTN)DestinationDirectory,
- (PSTR)DestinationPath,
- strlen(DestinationPath) + 1);
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- return 0;
- }
- LIBC_API
- ssize_t
- write (
- int FileDescriptor,
- const void *Buffer,
- size_t ByteCount
- )
- /*++
- Routine Description:
- This routine attempts to write the specifed number of bytes to the given
- open file descriptor.
- Arguments:
- FileDescriptor - Supplies the file descriptor returned by the open function.
- Buffer - Supplies a pointer to the buffer containing the bytes to be
- written.
- ByteCount - Supplies the number of bytes to write.
- Return Value:
- Returns the number of bytes successfully written to the file.
- -1 on failure, and errno will contain more information.
- --*/
- {
- UINTN BytesCompleted;
- KSTATUS Status;
- //
- // Truncate the byte count, so that it does not exceed the maximum number
- // of bytes that can be returned.
- //
- if (ByteCount > (size_t)SSIZE_MAX) {
- ByteCount = (size_t)SSIZE_MAX;
- }
- //
- // Ask the OS to actually do the I/O.
- //
- Status = OsPerformIo((HANDLE)(UINTN)FileDescriptor,
- IO_OFFSET_NONE,
- ByteCount,
- SYS_IO_FLAG_WRITE,
- SYS_WAIT_TIME_INDEFINITE,
- (PVOID)Buffer,
- &BytesCompleted);
- if (Status == STATUS_TIMEOUT) {
- errno = EAGAIN;
- return -1;
- } else if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- BytesCompleted = -1;
- }
- return (ssize_t)BytesCompleted;
- }
- LIBC_API
- ssize_t
- pwrite (
- int FileDescriptor,
- const void *Buffer,
- size_t ByteCount,
- off_t Offset
- )
- /*++
- Routine Description:
- This routine attempts to write the specifed number of bytes to the given
- open file descriptor at a given offset. It does not update the current
- file position.
- Arguments:
- FileDescriptor - Supplies the file descriptor returned by the open function.
- Buffer - Supplies a pointer to the buffer containing the bytes to be
- written.
- ByteCount - Supplies the number of bytes to write.
- Offset - Supplies the offset from the start of the file to write to.
- Return Value:
- Returns the number of bytes successfully written to the file.
- -1 on failure, and errno will contain more information.
- --*/
- {
- UINTN BytesCompleted;
- KSTATUS Status;
- //
- // Truncate the byte count, so that it does not exceed the maximum number
- // of bytes that can be returned.
- //
- if (ByteCount > (size_t)SSIZE_MAX) {
- ByteCount = (size_t)SSIZE_MAX;
- }
- //
- // Ask the OS to actually do the I/O.
- //
- Status = OsPerformIo((HANDLE)(UINTN)FileDescriptor,
- Offset,
- ByteCount,
- SYS_IO_FLAG_WRITE,
- SYS_WAIT_TIME_INDEFINITE,
- (PVOID)Buffer,
- &BytesCompleted);
- if (Status == STATUS_TIMEOUT) {
- errno = EAGAIN;
- return -1;
- } else if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- BytesCompleted = -1;
- }
- return (ssize_t)BytesCompleted;
- }
- LIBC_API
- int
- fsync (
- int FileDescriptor
- )
- /*++
- Routine Description:
- This routine flushes all the data associated with the open file descriptor
- to its corresponding backing device. It does not return until the data has
- been flushed.
- Arguments:
- FileDescriptor - Supplies the file descriptor returned by the open function.
- Return Value:
- 0 on success.
- -1 on failure, and the errno variable will be set to contain more
- information.
- --*/
- {
- KSTATUS Status;
- Status = OsFlush((HANDLE)(UINTN)FileDescriptor, 0);
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- return 0;
- }
- LIBC_API
- int
- fdatasync (
- int FileDescriptor
- )
- /*++
- Routine Description:
- This routine flushes all the data associated with the open file descriptor
- to its corresponding backing device. It does not return until the data has
- been flushed. It is similar to fsync but does not flush modified metadata
- if that metadata is unimportant to retrieving the file later. For example,
- last access and modified times wouldn't require a metadata flush, but file
- size change would.
- Arguments:
- FileDescriptor - Supplies the file descriptor returned by the open function.
- Return Value:
- 0 on success.
- -1 on failure, and the errno variable will be set to contain more
- information.
- --*/
- {
- //
- // For now, there is no actual distinction between this function and fsync.
- //
- return fsync(FileDescriptor);
- }
- LIBC_API
- void
- sync (
- void
- )
- /*++
- Routine Description:
- This routine schedules a flush for all file system related data that is in
- memory. Upon return, it is not guaranteed that the writing of the data is
- complete.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- OsFlush(INVALID_HANDLE, SYS_FLUSH_FLAG_ALL);
- return;
- }
- LIBC_API
- off_t
- lseek (
- int FileDescriptor,
- off_t Offset,
- int Whence
- )
- /*++
- Routine Description:
- This routine sets the file offset for the open file descriptor.
- Arguments:
- FileDescriptor - Supplies the file descriptor returned by the open function.
- Offset - Supplies the offset from the reference location given in the
- Whence argument.
- Whence - Supplies the reference location to base the offset off of. Valid
- value are:
- SEEK_SET - The offset will be added to the the beginning of the file.
- SEEK_CUR - The offset will be added to the current file position.
- SEEK_END - The offset will be added to the end of the file.
- Return Value:
- Returns the resulting file offset after the operation.
- -1 on failure, and errno will contain more information. The file offset
- will remain unchanged.
- --*/
- {
- IO_OFFSET NewOffset;
- SEEK_COMMAND SeekCommand;
- KSTATUS Status;
- switch (Whence) {
- case SEEK_SET:
- SeekCommand = SeekCommandFromBeginning;
- break;
- case SEEK_CUR:
- SeekCommand = SeekCommandFromCurrentOffset;
- break;
- case SEEK_END:
- SeekCommand = SeekCommandFromEnd;
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- goto lseekEnd;
- }
- Status = OsSeek((HANDLE)(UINTN)FileDescriptor,
- SeekCommand,
- Offset,
- &NewOffset);
- if (!KSUCCESS(Status)) {
- goto lseekEnd;
- }
- lseekEnd:
- if (!KSUCCESS(Status)) {
- if (Status == STATUS_NOT_SUPPORTED) {
- errno = ESPIPE;
- } else {
- errno = ClConvertKstatusToErrorNumber(Status);
- }
- return (off_t)-1;
- }
- return (off_t)NewOffset;
- }
- LIBC_API
- int
- ftruncate (
- int FileDescriptor,
- off_t NewSize
- )
- /*++
- Routine Description:
- This routine sets the file size of the given file descriptor. If the new
- size is smaller than the original size, then the remaining data will be
- discarded. If the new size is larger than the original size, then the
- extra space will be filled with zeroes.
- Arguments:
- FileDescriptor - Supplies the file descriptor whose size should be
- modified.
- NewSize - Supplies the new size of the file descriptor in bytes.
- Return Value:
- 0 on success.
- -1 on failure. The errno variable will be set to indicate the error.
- --*/
- {
- FILE_CONTROL_PARAMETERS_UNION Parameters;
- FILE_PROPERTIES Properties;
- KSTATUS Status;
- Properties.Size = NewSize;
- Parameters.SetFileInformation.FieldsToSet = FILE_PROPERTY_FIELD_FILE_SIZE;
- Parameters.SetFileInformation.FileProperties = &Properties;
- Status = OsFileControl((HANDLE)(UINTN)FileDescriptor,
- FileControlCommandSetFileInformation,
- &Parameters);
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- return 0;
- }
- LIBC_API
- int
- truncate (
- const char *Path,
- off_t NewSize
- )
- /*++
- Routine Description:
- This routine sets the file size of the given file path. If the new size is
- smaller than the original size, then the remaining data will be discarded.
- If the new size is larger than the original size, then the extra space will
- be filled with zeroes.
- Arguments:
- Path - Supplies a pointer to a null terminated string containing the path
- of the file whose size should be changed.
- NewSize - Supplies the new size of the file descriptor in bytes.
- Return Value:
- 0 on success.
- -1 on failure. The errno variable will be set to indicate the error.
- --*/
- {
- FILE_PROPERTIES Properties;
- SET_FILE_INFORMATION Request;
- KSTATUS Status;
- Properties.Size = NewSize;
- Request.FieldsToSet = FILE_PROPERTY_FIELD_FILE_SIZE;
- Request.FileProperties = &Properties;
- Status = OsSetFileInformation(INVALID_HANDLE,
- (PSTR)Path,
- strlen(Path) + 1,
- TRUE,
- &Request);
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- return 0;
- }
- LIBC_API
- int
- pipe (
- int FileDescriptors[2]
- )
- /*++
- Routine Description:
- This routine creates an anonymous pipe.
- Arguments:
- FileDescriptors - Supplies a pointer where handles will be returned
- representing the read and write ends of the pipe.
- Return Value:
- 0 on success.
- -1 on failure. The errno variable will be set to indicate the error.
- --*/
- {
- return pipe2(FileDescriptors, 0);
- }
- LIBC_API
- int
- pipe2 (
- int FileDescriptors[2],
- int Flags
- )
- /*++
- Routine Description:
- This routine creates an anonymous pipe.
- Arguments:
- FileDescriptors - Supplies a pointer where handles will be returned
- representing the read and write ends of the pipe.
- Flags - Supplies a bitfield of open flags governing the behavior of the new
- descriptors. Only O_NONBLOCK and O_CLOEXEC are honored.
- Return Value:
- 0 on success.
- -1 on failure. The errno variable will be set to indicate the error.
- --*/
- {
- ULONG OpenFlags;
- ULONG Permissions;
- HANDLE ReadHandle;
- KSTATUS Status;
- HANDLE WriteHandle;
- Permissions = FILE_PERMISSION_USER_READ | FILE_PERMISSION_USER_WRITE;
- OpenFlags = 0;
- if ((Flags & O_CLOEXEC) != 0) {
- OpenFlags |= SYS_OPEN_FLAG_CLOSE_ON_EXECUTE;
- }
- if ((Flags & O_NONBLOCK) != 0) {
- OpenFlags |= SYS_OPEN_FLAG_NON_BLOCKING;
- }
- Status = OsCreatePipe(INVALID_HANDLE,
- NULL,
- 0,
- OpenFlags,
- Permissions,
- &ReadHandle,
- &WriteHandle);
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- FileDescriptors[0] = (int)(UINTN)ReadHandle;
- FileDescriptors[1] = (int)(UINTN)WriteHandle;
- return 0;
- }
- LIBC_API
- int
- symlink (
- const char *LinkTarget,
- const char *LinkName
- )
- /*++
- Routine Description:
- This routine creates a symbolic link with the given name pointed at the
- supplied target path.
- Arguments:
- LinkTarget - Supplies the location that the link points to.
- LinkName - Supplies the path where the link should be created.
- Return Value:
- 0 on success.
- -1 on failure, and errno will be set to contain more information.
- --*/
- {
- return symlinkat(LinkTarget, AT_FDCWD, LinkName);
- }
- LIBC_API
- int
- symlinkat (
- const char *LinkTarget,
- int Directory,
- const char *LinkName
- )
- /*++
- Routine Description:
- This routine creates a symbolic link with the given name pointed at the
- supplied target path.
- Arguments:
- LinkTarget - Supplies the location that the link points to.
- Directory - Supplies an optional file descriptor. If the given path to the
- link name is a relative path, the directory referenced by this
- descriptor will be used as a starting point for path resolution. Supply
- AT_FDCWD to use the working directory for relative paths.
- LinkName - Supplies the path where the link should be created.
- Return Value:
- 0 on success.
- -1 on failure, and errno will be set to contain more information.
- --*/
- {
- KSTATUS Status;
- Status = OsCreateSymbolicLink((HANDLE)(UINTN)Directory,
- (PSTR)LinkName,
- strlen(LinkName) + 1,
- (PSTR)LinkTarget,
- strlen(LinkTarget));
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- return 0;
- }
- LIBC_API
- ssize_t
- readlink (
- const char *Path,
- char *LinkDestinationBuffer,
- size_t LinkDestinationBufferSize
- )
- /*++
- Routine Description:
- This routine reads the destination path of a symbolic link.
- Arguments:
- Path - Supplies a pointer to the symbolic link path.
- LinkDestinationBuffer - Supplies a pointer to a buffer where the
- destination of the link will be returned. A null terminator is not
- written.
- LinkDestinationBufferSize - Supplies the size of the link destination
- buffer in bytes.
- Return Value:
- Returns the number of bytes placed into the buffer on success.
- -1 on failure. The errno variable will be set to indicate the error, and
- the buffer will remain unchanged.
- --*/
- {
- ssize_t Result;
- Result = readlinkat(AT_FDCWD,
- Path,
- LinkDestinationBuffer,
- LinkDestinationBufferSize);
- return Result;
- }
- LIBC_API
- ssize_t
- readlinkat (
- int Directory,
- const char *Path,
- char *LinkDestinationBuffer,
- size_t LinkDestinationBufferSize
- )
- /*++
- Routine Description:
- This routine reads the destination path of a symbolic link.
- Arguments:
- Directory - Supplies an optional file descriptor. If the given path
- is a relative path, the directory referenced by this descriptor will
- be used as a starting point for path resolution. Supply AT_FDCWD to
- use the working directory for relative paths.
- Path - Supplies a pointer to the symbolic link path.
- LinkDestinationBuffer - Supplies a pointer to a buffer where the
- destination of the link will be returned. A null terminator is not
- written.
- LinkDestinationBufferSize - Supplies the size of the link destination
- buffer in bytes.
- Return Value:
- Returns the number of bytes placed into the buffer on success.
- -1 on failure. The errno variable will be set to indicate the error, and
- the buffer will remain unchanged.
- --*/
- {
- ULONG LinkDestinationSize;
- KSTATUS Status;
- Status = OsReadSymbolicLink((HANDLE)(UINTN)Directory,
- (PSTR)Path,
- strlen(Path) + 1,
- LinkDestinationBuffer,
- LinkDestinationBufferSize,
- &LinkDestinationSize);
- if (!KSUCCESS(Status)) {
- if (Status == STATUS_BUFFER_TOO_SMALL) {
- errno = ERANGE;
- } else {
- errno = ClConvertKstatusToErrorNumber(Status);
- }
- return -1;
- }
- return LinkDestinationSize;
- }
- LIBC_API
- int
- link (
- const char *ExistingFile,
- const char *LinkPath
- )
- /*++
- Routine Description:
- This routine creates a hard link to the given file.
- Arguments:
- ExistingFile - Supplies a pointer to a null-terminated string containing
- the path to the file that already exists.
- LinkPath - Supplies a pointer to a null-terminated string containing the
- path of the new link to create.
- Return Value:
- 0 on success.
- -1 on failure. The errno variable will be set to indicate the error.
- --*/
- {
- return linkat(AT_FDCWD, ExistingFile, AT_FDCWD, LinkPath, 0);
- }
- LIBC_API
- int
- linkat (
- int ExistingFileDirectory,
- const char *ExistingFile,
- int LinkPathDirectory,
- const char *LinkPath,
- int Flags
- )
- /*++
- Routine Description:
- This routine creates a hard link to the given file.
- Arguments:
- ExistingFileDirectory - Supplies an optional file descriptor. If the given
- existing file path is a relative path, the directory referenced by this
- descriptor will be used as a starting point for path resolution. Supply
- AT_FDCWD to use the working directory for relative paths.
- ExistingFile - Supplies a pointer to a null-terminated string containing
- the path to the file that already exists.
- LinkPathDirectory - Supplies an optional file descriptor. If the given new
- link is a relative path, the directory referenced by this descriptor
- will be used as a starting point for path resolution. Supply AT_FDCWD
- to use the working directory for relative paths.
- LinkPath - Supplies a pointer to a null-terminated string containing the
- path of the new link to create.
- Flags - Supplies AT_SYMLINK_FOLLOW if the routine should link to the
- destination of the symbolic link if the existing file path is a
- symbolic link. Supply 0 to create a link to the symbolic link itself.
- Return Value:
- 0 on success.
- -1 on failure. The errno variable will be set to indicate the error.
- --*/
- {
- BOOL FollowLinks;
- KSTATUS Status;
- FollowLinks = FALSE;
- if ((Flags & AT_SYMLINK_FOLLOW) != 0) {
- FollowLinks = TRUE;
- }
- Status = OsCreateHardLink((HANDLE)(UINTN)ExistingFileDirectory,
- (PSTR)ExistingFile,
- strlen(ExistingFile) + 1,
- (HANDLE)(UINTN)LinkPathDirectory,
- (PSTR)LinkPath,
- strlen(LinkPath) + 1,
- FollowLinks);
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- return 0;
- }
- LIBC_API
- int
- remove (
- const char *Path
- )
- /*++
- Routine Description:
- This routine attempts to delete the object at the given path. If the
- object pointed to by the given path is a directory, the behavior of remove
- is identical to rmdir. Otherwise, the behavior of remove is identical to
- unlink.
- Arguments:
- Path - Supplies a pointer to a null terminated string containing the path
- of the entry to remove.
- Return Value:
- 0 on success.
- -1 on failure, and errno will be set to provide more details. In failure
- cases, the directory will not be removed.
- --*/
- {
- int Result;
- struct stat Stat;
- Result = lstat(Path, &Stat);
- if (Result < 0) {
- return Result;
- }
- if (S_ISDIR(Stat.st_mode)) {
- return rmdir(Path);
- }
- return unlink(Path);
- }
- LIBC_API
- int
- unlink (
- const char *Path
- )
- /*++
- Routine Description:
- This routine attempts to delete the object at the given path. If the path
- points to a directory, the directory must be empty. If the path points to
- a file, the hard link count on the file is decremented. If the hard link
- count reaches zero and no processes have the file open, the contents of the
- file are destroyed. If processes have open handles to the file, the
- destruction of the file contents are deferred until the last handle to the
- old file is closed. If the path points to a symbolic link, the link itself
- is removed and not the destination. The removal of the entry from the
- directory is immediate.
- Arguments:
- Path - Supplies a pointer to a null terminated string containing the path
- of the entry to remove.
- Return Value:
- 0 on success.
- -1 on failure, and errno will be set to provide more details. In failure
- cases, the directory will not be removed.
- --*/
- {
- return unlinkat(AT_FDCWD, Path, 0);
- }
- LIBC_API
- int
- unlinkat (
- int Directory,
- const char *Path,
- int Flags
- )
- /*++
- Routine Description:
- This routine attempts to delete the object at the given path. If the path
- points to a directory, the directory must be empty. If the path points to
- a file, the hard link count on the file is decremented. If the hard link
- count reaches zero and no processes have the file open, the contents of the
- file are destroyed. If processes have open handles to the file, the
- destruction of the file contents are deferred until the last handle to the
- old file is closed. If the path points to a symbolic link, the link itself
- is removed and not the destination. The removal of the entry from the
- directory is immediate.
- Arguments:
- Directory - Supplies an optional file descriptor. If the given path
- is a relative path, the directory referenced by this descriptor will
- be used as a starting point for path resolution. Supply AT_FDCWD to
- use the working directory for relative paths.
- Path - Supplies a pointer to a null terminated string containing the path
- of the entry to remove.
- Flags - Supplies a bitfield of flags. Supply AT_REMOVEDIR to attempt to
- remove a directory (and only a directory). Supply zero to attempt to
- remove a non-directory.
- Return Value:
- 0 on success.
- -1 on failure, and errno will be set to provide more details. In failure
- cases, the directory will not be removed.
- --*/
- {
- ULONG OsFlags;
- KSTATUS Status;
- OsFlags = 0;
- if ((Flags & AT_REMOVEDIR) != 0) {
- OsFlags |= SYS_DELETE_FLAG_DIRECTORY;
- }
- if (Path == NULL) {
- errno = EFAULT;
- return -1;
- }
- Status = OsDelete((HANDLE)(UINTN)Directory,
- (PSTR)Path,
- strlen(Path) + 1,
- OsFlags);
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- return 0;
- }
- LIBC_API
- int
- dup (
- int FileDescriptor
- )
- /*++
- Routine Description:
- This routine duplicates the given file descriptor.
- Arguments:
- FileDescriptor - Supplies the file descriptor to duplicate.
- Return Value:
- Returns the new file descriptor which represents a copy of the original
- file descriptor.
- -1 on failure, and errno will be set to contain more information.
- --*/
- {
- HANDLE NewHandle;
- KSTATUS Status;
- NewHandle = INVALID_HANDLE;
- Status = OsDuplicateHandle((HANDLE)(UINTN)FileDescriptor, &NewHandle, 0);
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- return (int)(UINTN)NewHandle;
- }
- LIBC_API
- int
- dup2 (
- int FileDescriptor,
- int CopyDescriptor
- )
- /*++
- Routine Description:
- This routine duplicates the given file descriptor to the destination
- descriptor, closing the original destination descriptor file along the way.
- Arguments:
- FileDescriptor - Supplies the file descriptor to duplicate.
- CopyDescriptor - Supplies the descriptor number of returned copy.
- Return Value:
- Returns the new file descriptor which represents a copy of the original,
- which is also equal to the input copy descriptor parameter.
- -1 on failure, and errno will be set to contain more information.
- --*/
- {
- HANDLE NewHandle;
- KSTATUS Status;
- NewHandle = (HANDLE)(UINTN)CopyDescriptor;
- if (CopyDescriptor < 0) {
- errno = EBADF;
- return -1;
- }
- Status = OsDuplicateHandle((HANDLE)(UINTN)FileDescriptor, &NewHandle, 0);
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- assert(NewHandle == (HANDLE)(UINTN)CopyDescriptor);
- return (int)(UINTN)NewHandle;
- }
- LIBC_API
- int
- dup3 (
- int FileDescriptor,
- int CopyDescriptor,
- int Flags
- )
- /*++
- Routine Description:
- This routine duplicates the given file descriptor to the destination
- descriptor, closing the original destination descriptor file along the way.
- Arguments:
- FileDescriptor - Supplies the file descriptor to duplicate.
- CopyDescriptor - Supplies the descriptor number of returned copy. If this
- is equal to the original file descriptor, then the call fails with
- EINVAL.
- Flags - Supplies O_* open flags governing the new descriptor. Only
- O_CLOEXEC is permitted.
- Return Value:
- Returns the new file descriptor which represents a copy of the original,
- which is also equal to the input copy descriptor parameter.
- -1 on failure, and errno will be set to contain more information.
- --*/
- {
- HANDLE NewHandle;
- ULONG OpenFlags;
- KSTATUS Status;
- if (FileDescriptor == CopyDescriptor) {
- errno = EINVAL;
- return -1;
- }
- NewHandle = (HANDLE)(UINTN)CopyDescriptor;
- OpenFlags = 0;
- if ((Flags & O_CLOEXEC) != 0) {
- OpenFlags |= SYS_OPEN_FLAG_CLOSE_ON_EXECUTE;
- }
- Status = OsDuplicateHandle((HANDLE)(UINTN)FileDescriptor,
- &NewHandle,
- OpenFlags);
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- assert(NewHandle == (HANDLE)(UINTN)CopyDescriptor);
- return (int)(UINTN)NewHandle;
- }
- LIBC_API
- int
- lockf (
- int FileDescriptor,
- int Function,
- off_t Size
- )
- /*++
- Routine Description:
- This routine locks or unlocks sections of a file with advisory-mode locks.
- All locks for a process are removed when the process terminates. Record
- locking is supported at least for regular files, and may be supported for
- other file types.
- Arguments:
- FileDescriptor - Supplies the file descriptor to query. To establish a
- lock, the given file descriptor must be opened with O_WRONLY or O_RDWR.
- Function - Supplies the action to be taken. Valid values are:
- F_ULOCK - Unlocks a locked section.
- F_LOCK - Locks a section for exclusive use (blocking if already locked).
- F_TLOCK - Test and lock for exclusive use, not blocking.
- F_TEST - Test for a section of locks by other processes.
- Size - Supplies the number of contiguous bytes to be locked or unlocked.
- The section to be locked or unlocked starts at the current offset in
- the file and extends forward for a positve size or backwards for a
- negative size (the preceding bytes up to but not including the current
- offset). If size is 0, the section from the current offset through the
- largest possible offset shall be locked. Locks may exist past the
- current end of file.
- Return Value:
- 0 on success.
- -1 on error, and errno will be set to contain more information. The errno
- variable may be set to the following values:
- EACCES or EAGAIN if the function argument is F_TLOCK or F_TEST and the
- section is already locked by another process.
- EDEADLK if the function argument is F_LOCK and a deadlock is detected.
- EINVAL if the function is valid or the size plus the current offset is less
- than zero.
- EOVERFLOW if the range cannot properly be represented in an off_t.
- --*/
- {
- int ControlOperation;
- struct flock Parameters;
- Parameters.l_start = 0;
- Parameters.l_len = Size;
- Parameters.l_pid = 0;
- Parameters.l_type = F_WRLCK;
- Parameters.l_whence = SEEK_CUR;
- if (Function == F_ULOCK) {
- ControlOperation = F_SETLK;
- Parameters.l_type = F_UNLCK;
- } else if (Function == F_LOCK) {
- ControlOperation = F_SETLKW;
- } else if (Function == F_TLOCK) {
- ControlOperation = F_SETLK;
- } else if (Function == F_TEST) {
- ControlOperation = F_GETLK;
- } else {
- errno = EINVAL;
- return -1;
- }
- return fcntl(FileDescriptor, ControlOperation, &Parameters);
- }
- LIBC_API
- int
- dprintf (
- int FileDescriptor,
- const char *Format,
- ...
- )
- /*++
- Routine Description:
- This routine prints a formatted string to the given file descriptor.
- Arguments:
- FileDescriptor - Supplies the file descriptor to print to.
- Format - Supplies the printf format string.
- ... - Supplies a variable number of arguments, as required by the printf
- format string argument.
- Return Value:
- Returns the number of bytes successfully converted, not including the null
- terminator.
- Returns a negative number if an error was encountered.
- --*/
- {
- va_list Arguments;
- int Result;
- va_start(Arguments, Format);
- Result = vdprintf(FileDescriptor, Format, Arguments);
- va_end(Arguments);
- return Result;
- }
- LIBC_API
- int
- vdprintf (
- int FileDescriptor,
- const char *Format,
- va_list Arguments
- )
- /*++
- Routine Description:
- This routine prints a formatted string to the given file descriptor.
- Arguments:
- FileDescriptor - Supplies the file descriptor to print to.
- Format - Supplies the printf format string.
- Arguments - Supplies the argument list to the format string. The va_end
- macro is not invoked on this list.
- Return Value:
- Returns the number of bytes successfully converted. A null terminator is
- not written.
- Returns a negative number if an error was encountered.
- --*/
- {
- int Result;
- PSTR String;
- size_t TotalWritten;
- ssize_t Written;
- String = NULL;
- Result = vasprintf(&String, Format, Arguments);
- if (Result <= 0) {
- return Result;
- }
- TotalWritten = 0;
- while (TotalWritten < Result) {
- do {
- Written = write(FileDescriptor,
- String + TotalWritten,
- Result - TotalWritten);
- } while ((Written < 0) && (errno == EINTR));
- if (Written <= 0) {
- Result = Written;
- break;
- }
- TotalWritten += Written;
- }
- free(String);
- return Result;
- }
- LIBC_API
- int
- sprintf (
- char *OutputString,
- const char *Format,
- ...
- )
- /*++
- Routine Description:
- This routine prints a formatted string to the given buffer. This routine
- should be avoided if possible as it can be the cause of buffer overflow
- issues. Use snprintf instead, a function that explicitly bounds the output
- buffer.
- Arguments:
- OutputString - Supplies the buffer where the formatted string will be
- returned. It is the caller's responsibility to ensure this buffer is
- large enough to hold the formatted string.
- Format - Supplies the printf format string.
- ... - Supplies a variable number of arguments, as required by the printf
- format string argument.
- Return Value:
- Returns the number of bytes successfully converted, not including the null
- terminator.
- Returns a negative number if an error was encountered.
- --*/
- {
- va_list Arguments;
- int Result;
- va_start(Arguments, Format);
- Result = vsprintf(OutputString, Format, Arguments);
- va_end(Arguments);
- return Result;
- }
- LIBC_API
- int
- snprintf (
- char *OutputString,
- size_t OutputStringSize,
- const char *Format,
- ...
- )
- /*++
- Routine Description:
- This routine prints a formatted string to the given bounded buffer.
- Arguments:
- OutputString - Supplies the buffer where the formatted string will be
- returned.
- OutputStringSize - Supplies the number of bytes in the output buffer.
- Format - Supplies the printf format string.
- ... - Supplies a variable number of arguments, as required by the printf
- format string argument.
- Return Value:
- Returns the number of bytes that would have been converted had
- OutputStringSize been large enough, not including the null terminator.
- Returns a negative number if an error was encountered.
- --*/
- {
- va_list Arguments;
- int Result;
- va_start(Arguments, Format);
- Result = vsnprintf(OutputString, OutputStringSize, Format, Arguments);
- va_end(Arguments);
- return Result;
- }
- LIBC_API
- int
- vsnprintf (
- char *OutputString,
- size_t OutputStringSize,
- const char *Format,
- va_list Arguments
- )
- /*++
- Routine Description:
- This routine implements the core string print format function.
- Arguments:
- OutputString - Supplies a pointer to the buffer where the resulting string
- will be written.
- OutputStringSize - Supplies the size of the output string buffer, in bytes.
- If the format is too long for the output buffer, the resulting string
- will be truncated and the last byte will always be a null terminator.
- Format - Supplies the printf format string.
- Arguments - Supplies the argument list to the format string. The va_end
- macro is not invoked on this list.
- Return Value:
- Returns the number of bytes that would have been converted had
- OutputStringSize been large enough, not including the null terminator.
- Returns a negative number if an error was encountered.
- --*/
- {
- ULONG Result;
- Result = RtlFormatString(OutputString,
- OutputStringSize,
- CharacterEncodingDefault,
- (PSTR)Format,
- Arguments);
- return Result - 1;
- }
- LIBC_API
- int
- vsprintf (
- char *OutputString,
- const char *Format,
- va_list Arguments
- )
- /*++
- Routine Description:
- This routine implements the core string print format function.
- Arguments:
- OutputString - Supplies a pointer to the buffer where the resulting string
- will be written.
- Format - Supplies the printf format string.
- Arguments - Supplies the argument list to the format string. The va_end
- macro is not invoked on this list.
- Return Value:
- Returns the number of bytes successfully converted, not including the null
- terminator.
- Returns a negative number if an error was encountered.
- --*/
- {
- return vsnprintf(OutputString, MAX_LONG, Format, Arguments);
- }
- LIBC_API
- int
- asprintf (
- char **OutputString,
- const char *Format,
- ...
- )
- /*++
- Routine Description:
- This routine prints a formatting string to a string similar to vsnprintf,
- except the destination string is allocated by this function using malloc.
- Arguments:
- OutputString - Supplies a pointer where a pointer to a newly allocated
- buffer containing the formatted string result (including the null
- terminator) will be returned. The caller is reponsible for freeing this
- string.
- Format - Supplies the printf format string.
- ... - Supplies the argument list to the format string.
- Return Value:
- Returns the number of bytes successfully converted, not including the null
- terminator.
- Returns a negative number if an error was encountered.
- --*/
- {
- va_list Arguments;
- int Status;
- va_start(Arguments, Format);
- Status = vasprintf(OutputString, Format, Arguments);
- va_end(Arguments);
- return Status;
- }
- LIBC_API
- int
- vasprintf (
- char **OutputString,
- const char *Format,
- va_list Arguments
- )
- /*++
- Routine Description:
- This routine prints a formatting string to a string similar to vsnprintf,
- except the destination string is allocated by this function using malloc.
- Arguments:
- OutputString - Supplies a pointer where a pointer to a newly allocated
- buffer containing the formatted string result (including the null
- terminator) will be returned. The caller is reponsible for freeing this
- string.
- Format - Supplies the printf format string.
- Arguments - Supplies the argument list to the format string. The va_end
- macro is not invoked on this list.
- Return Value:
- Returns the number of bytes successfully converted, not including the null
- terminator.
- Returns a negative number if an error was encountered.
- --*/
- {
- ASPRINT_CONTEXT AsContext;
- PRINT_FORMAT_CONTEXT PrintContext;
- *OutputString = NULL;
- memset(&PrintContext, 0, sizeof(PRINT_FORMAT_CONTEXT));
- PrintContext.Context = &AsContext;
- PrintContext.WriteCharacter = ClpAsPrintWriteCharacter;
- RtlInitializeMultibyteState(&(PrintContext.State),
- CharacterEncodingDefault);
- AsContext.Buffer = malloc(ASPRINT_INITIAL_BUFFER_SIZE);
- if (AsContext.Buffer == NULL) {
- return -1;
- }
- AsContext.Size = 0;
- AsContext.Capacity = ASPRINT_INITIAL_BUFFER_SIZE;
- RtlFormat(&PrintContext, (PSTR)Format, Arguments);
- if (AsContext.Buffer == NULL) {
- return -1;
- }
- ASSERT(AsContext.Size < AsContext.Capacity);
- AsContext.Buffer[AsContext.Size] = '\0';
- *OutputString = AsContext.Buffer;
- return PrintContext.CharactersWritten;
- }
- LIBC_API
- int
- poll (
- struct pollfd PollDescriptors[],
- nfds_t DescriptorCount,
- int Timeout
- )
- /*++
- Routine Description:
- This routine blocks waiting for specified activity on a range of file
- descriptors.
- Arguments:
- PollDescriptors - Supplies an array of poll descriptor structures,
- indicating which descriptors should be waited on and which events
- should qualify in each descriptor.
- DescriptorCount - Supplies the number of descriptors in the array.
- Timeout - Supplies the amount of time in milliseconds to block before
- giving up and returning anyway. Supply 0 to not block at all, and
- supply -1 to wait for an indefinite amount of time. The timeout will be
- at least as long as supplied, but may also be rounded up.
- Return Value:
- Returns a positive number to indicate success and the number of file
- descriptors that had events occur.
- Returns 0 to indicate a timeout.
- Returns -1 to indicate an error, and errno will be set to contain more
- information.
- --*/
- {
- struct timespec *TimeoutPointer;
- struct timespec Timespec;
- if (Timeout >= 0) {
- Timespec.tv_sec = Timeout / MILLISECONDS_PER_SECOND;
- Timespec.tv_nsec = (Timeout % MILLISECONDS_PER_SECOND) *
- NANOSECONDS_PER_MILLISECOND;
- TimeoutPointer = &Timespec;
- } else {
- TimeoutPointer = NULL;
- }
- return ppoll(PollDescriptors, DescriptorCount, TimeoutPointer, NULL);
- }
- LIBC_API
- int
- ppoll (
- struct pollfd PollDescriptors[],
- nfds_t DescriptorCount,
- const struct timespec *Timeout,
- const sigset_t *SignalMask
- )
- /*++
- Routine Description:
- This routine blocks waiting for specified activity on a range of file
- descriptors.
- Arguments:
- PollDescriptors - Supplies an array of poll descriptor structures,
- indicating which descriptors should be waited on and which events
- should qualify in each descriptor.
- DescriptorCount - Supplies the number of descriptors in the array.
- Timeout - Supplies the amount of time to block before giving up and
- returning anyway. Supply 0 to not block at all, and supply -1 to wait
- for an indefinite amount of time. The timeout will be at least as long
- as supplied, but may also be rounded up.
- SignalMask - Supplies an optional pointer to a signal mask to set
- atomically for the duration of the wait.
- Return Value:
- Returns a positive number to indicate success and the number of file
- descriptors that had events occur.
- Returns 0 to indicate a timeout.
- Returns -1 to indicate an error, and errno will be set to contain more
- information.
- --*/
- {
- ULONG DescriptorsSelected;
- INT Result;
- KSTATUS Status;
- ULONG TimeoutMilliseconds;
- if (DescriptorCount > sysconf(_SC_OPEN_MAX)) {
- errno = EINVAL;
- return -1;
- }
- ASSERT_POLL_FLAGS_EQUIVALENT();
- ASSERT_POLL_STRUCTURE_EQUIVALENT();
- Result = ClpConvertSpecificTimeoutToSystemTimeout(Timeout,
- &TimeoutMilliseconds);
- if (Result != 0) {
- errno = Result;
- return -1;
- }
- //
- // Perform the actual poll call, and return if failure is received.
- //
- Status = OsPoll((PSIGNAL_SET)SignalMask,
- (PPOLL_DESCRIPTOR)PollDescriptors,
- DescriptorCount,
- TimeoutMilliseconds,
- &DescriptorsSelected);
- if (!KSUCCESS(Status)) {
- goto pollEnd;
- }
- pollEnd:
- if ((!KSUCCESS(Status)) && (Status != STATUS_TIMEOUT)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- return (int)DescriptorsSelected;
- }
- LIBC_API
- int
- select (
- int DescriptorCount,
- fd_set *ReadDescriptors,
- fd_set *WriteDescriptors,
- fd_set *ErrorDescriptors,
- struct timeval *Timeout
- )
- /*++
- Routine Description:
- This routine indicates which of the specified file descriptors are ready
- for reading, writing, and have error conditions.
- Arguments:
- DescriptorCount - Supplies the range of file descriptors to be tested.
- This routine tests file descriptors in the range of 0 to the descriptor
- count - 1.
- ReadDescriptors - Supplies an optional pointer to a set of descriptors that
- on input supplies the set of descriptors to be checked for reading. On
- output, contains the set of descriptors that are ready to be read.
- WriteDescriptors - Supplies an optional pointer to a set of descriptors that
- on input supplies the set of descriptors to be checked for writing. On
- output, contains the set of descriptors that are ready to be written to.
- ErrorDescriptors - Supplies an optional pointer to a set of descriptors that
- on input supplies the set of descriptors to be checked for errors. On
- output, contains the set of descriptors that have errors.
- Timeout - Supplies an optional to a structure that defines how long to wait
- for one or more of the descriptors to become ready. If all members of
- this structure are 0, the function will not block. If this argument is
- not supplied, the function will block indefinitely until one of the
- events is ready. If all three descriptor structure pointers is null,
- this routine will block for the specified amount of time and then
- return.
- Return Value:
- On success, returns the total number of bits set in the resulting bitmaps.
- 0 if the timeout expired.
- -1 on error, and errno will be set to contain more information.
- --*/
- {
- int Result;
- struct timespec *TimeoutPointer;
- struct timespec Timespec;
- if (Timeout != NULL) {
- Timespec.tv_sec = Timeout->tv_sec;
- Timespec.tv_nsec = Timeout->tv_usec * NANOSECONDS_PER_MICROSECOND;
- TimeoutPointer = &Timespec;
- } else {
- TimeoutPointer = NULL;
- }
- Result = pselect(DescriptorCount,
- ReadDescriptors,
- WriteDescriptors,
- ErrorDescriptors,
- TimeoutPointer,
- NULL);
- return Result;
- }
- LIBC_API
- int
- pselect (
- int DescriptorCount,
- fd_set *ReadDescriptors,
- fd_set *WriteDescriptors,
- fd_set *ErrorDescriptors,
- const struct timespec *Timeout,
- const sigset_t *SignalMask
- )
- /*++
- Routine Description:
- This routine indicates which of the specified file descriptors are ready
- for reading, writing, and have error conditions.
- Arguments:
- DescriptorCount - Supplies the range of file descriptors to be tested.
- This routine tests file descriptors in the range of 0 to the descriptor
- count - 1.
- ReadDescriptors - Supplies an optional pointer to a set of descriptors that
- on input supplies the set of descriptors to be checked for reading. On
- output, contains the set of descriptors that are ready to be read.
- WriteDescriptors - Supplies an optional pointer to a set of descriptors that
- on input supplies the set of descriptors to be checked for writing. On
- output, contains the set of descriptors that are ready to be written to.
- ErrorDescriptors - Supplies an optional pointer to a set of descriptors that
- on input supplies the set of descriptors to be checked for errors. On
- output, contains the set of descriptors that have errors.
- Timeout - Supplies an optional to a structure that defines how long to wait
- for one or more of the descriptors to become ready. If all members of
- this structure are 0, the function will not block. If this argument is
- not supplied, the function will block indefinitely until one of the
- events is ready. If all three descriptor structure pointers is null,
- this routine will block for the specified amount of time and then
- return.
- SignalMask - Supplies an optional pointer to the signal mask to set for
- the duration of the wait.
- Return Value:
- On success, returns the total number of bits set in the resulting bitmaps.
- 0 if the timeout expired.
- -1 on error, and errno will be set to contain more information.
- --*/
- {
- ULONG ArrayIndex;
- INT BitCount;
- PPOLL_DESCRIPTOR Descriptor;
- ULONG DescriptorIndex;
- PPOLL_DESCRIPTOR Descriptors;
- ULONG DescriptorsSelected;
- ULONG Events;
- ULONG PollIndex;
- INT Result;
- KSTATUS Status;
- ULONG TimeoutInMilliseconds;
- if (DescriptorCount < 0) {
- errno = EINVAL;
- return -1;
- }
- Result = ClpConvertSpecificTimeoutToSystemTimeout(Timeout,
- &TimeoutInMilliseconds);
- if (Result != 0) {
- errno = Result;
- return -1;
- }
- Descriptors = NULL;
- DescriptorsSelected = 0;
- if (DescriptorCount > FD_SETSIZE) {
- DescriptorCount = FD_SETSIZE;
- }
- Descriptors = alloca(sizeof(POLL_DESCRIPTOR) * DescriptorCount);
- if (Descriptors == NULL) {
- errno = ENOMEM;
- return -1;
- }
- //
- // Fill out the new poll descriptors.
- //
- ArrayIndex = 0;
- for (DescriptorIndex = 0;
- DescriptorIndex < DescriptorCount;
- DescriptorIndex += 1) {
- Events = 0;
- if ((ReadDescriptors != NULL) &&
- (FD_ISSET(DescriptorIndex, ReadDescriptors) != FALSE)) {
- Events |= POLL_EVENT_IN;
- }
- if ((WriteDescriptors != NULL) &&
- (FD_ISSET(DescriptorIndex, WriteDescriptors) != FALSE)) {
- Events |= POLL_EVENT_OUT;
- }
- if ((ErrorDescriptors != NULL) &&
- (FD_ISSET(DescriptorIndex, ErrorDescriptors) != FALSE)) {
- Events |= POLL_EVENT_ERROR;
- }
- if (Events == 0) {
- continue;
- }
- Descriptor = &(Descriptors[ArrayIndex]);
- ArrayIndex += 1;
- Descriptor->Handle = (HANDLE)(UINTN)DescriptorIndex;
- Descriptor->Events = Events;
- Descriptor->ReturnedEvents = 0;
- }
- //
- // Peform the poll.
- //
- Status = OsPoll((PSIGNAL_SET)SignalMask,
- Descriptors,
- ArrayIndex,
- TimeoutInMilliseconds,
- &DescriptorsSelected);
- if ((!KSUCCESS(Status)) && (Status != STATUS_TIMEOUT)) {
- goto pselectEnd;
- }
- //
- // Check for invalid handles, since POSIX says on failure the bitmasks
- // should not be modified.
- //
- for (PollIndex = 0; PollIndex < ArrayIndex; PollIndex += 1) {
- if ((Descriptors[PollIndex].ReturnedEvents &
- POLL_EVENT_INVALID_HANDLE) != 0) {
- Status = STATUS_INVALID_HANDLE;
- goto pselectEnd;
- }
- }
- //
- // Go back and mark all the descriptors in the set that had events. Loop
- // over the poll events this time to skip the empty regions of the bitmasks.
- //
- BitCount = 0;
- Descriptor = &(Descriptors[0]);
- for (PollIndex = 0; PollIndex < ArrayIndex; PollIndex += 1) {
- Events = Descriptor->ReturnedEvents;
- DescriptorIndex = (UINTN)(Descriptor->Handle);
- ASSERT(DescriptorIndex < DescriptorCount);
- //
- // If the caller didn't want error events but one fired, set the in and
- // out events to force them to take action.
- //
- if (((Events & POLL_ERROR_EVENTS) != 0) && (ErrorDescriptors == NULL)) {
- Events |= POLL_EVENT_IN | POLL_EVENT_OUT;
- }
- if ((ReadDescriptors != NULL) &&
- (FD_ISSET(DescriptorIndex, ReadDescriptors) != FALSE)) {
- if ((Events & POLL_EVENT_IN) == 0) {
- FD_CLR(DescriptorIndex, ReadDescriptors);
- } else {
- BitCount += 1;
- }
- }
- if ((WriteDescriptors != NULL) &&
- (FD_ISSET(DescriptorIndex, WriteDescriptors) != FALSE)) {
- if ((Events & POLL_EVENT_OUT) == 0) {
- FD_CLR(DescriptorIndex, WriteDescriptors);
- } else {
- BitCount += 1;
- }
- }
- //
- // Errors work a little differently, if it's supplied then the bits get
- // set whether they were asked for or not.
- //
- if (ErrorDescriptors != NULL) {
- if ((Events & POLL_NONMASKABLE_EVENTS) != 0) {
- FD_SET(DescriptorIndex, ErrorDescriptors);
- BitCount += 1;
- } else {
- FD_CLR(DescriptorIndex, ErrorDescriptors);
- }
- }
- Descriptor += 1;
- }
- pselectEnd:
- if (!KSUCCESS(Status)) {
- if (Status != STATUS_TIMEOUT) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- }
- return BitCount;
- }
- LIBC_API
- char *
- ttyname (
- int FileDescriptor
- )
- /*++
- Routine Description:
- This routine returns the null-terminated pathname of the terminal
- associated with the given file descriptor. This function is neither
- reentrant nor thread safe.
- Arguments:
- FileDescriptor - Supplies the file descriptor to query.
- Return Value:
- Returns a pointer to the supplied buffer on success. This buffer may be
- overwritten by subsequent calls to this routine.
- NULL on failure and errno will be set to contain more information. Common
- error values are:
- EBADF if the file descriptor is not valid.
- ENOTTY if the file descriptor is not a terminal.
- ENOMEM if not enough memory was available.
- --*/
- {
- char *NewBuffer;
- size_t NewBufferSize;
- int OldError;
- char *Result;
- if (ClTerminalNameBufferSize == 0) {
- ClTerminalNameBuffer = malloc(INITIAL_TERMINAL_NAME_BUFFER_SIZE);
- if (ClTerminalNameBuffer == NULL) {
- errno = ENOMEM;
- return NULL;
- }
- ClTerminalNameBufferSize = INITIAL_TERMINAL_NAME_BUFFER_SIZE;
- }
- OldError = errno;
- while (TRUE) {
- Result = ttyname_r(FileDescriptor,
- ClTerminalNameBuffer,
- ClTerminalNameBufferSize);
- if ((Result != NULL) || (errno != ERANGE)) {
- break;
- }
- errno = OldError;
- NewBufferSize = ClTerminalNameBufferSize * 2;
- NewBuffer = realloc(ClTerminalNameBuffer, NewBufferSize);
- if (NewBuffer == NULL) {
- errno = ENOMEM;
- return NULL;
- }
- ClTerminalNameBuffer = NewBuffer;
- ClTerminalNameBufferSize = NewBufferSize;
- }
- return Result;
- }
- LIBC_API
- char *
- ttyname_r (
- int FileDescriptor,
- char *Name,
- size_t NameSize
- )
- /*++
- Routine Description:
- This routine returns the null-terminated pathname of the terminal
- associated with the given file descriptor.
- Arguments:
- FileDescriptor - Supplies the file descriptor to query.
- Name - Supplies a pointer to the buffer where the name will be returned
- on success.
- NameSize - Supplies the size of the name buffer in bytes.
- Return Value:
- Returns a pointer to the supplied buffer on success.
- NULL on failure and errno will be set to contain more information. Common
- error values are:
- EBADF if the file descriptor is not valid.
- ENOTTY if the file descriptor is not a terminal.
- ERANGE if the supplied buffer was not large enough.
- --*/
- {
- UINTN Size;
- KSTATUS Status;
- if (isatty(FileDescriptor) == 0) {
- errno = ENOTTY;
- return NULL;
- }
- Size = NameSize;
- Status = OsGetFilePath((HANDLE)(UINTN)FileDescriptor, Name, &Size);
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return NULL;
- }
- return Name;
- }
- LIBC_API
- char *
- ctermid (
- char *Buffer
- )
- /*++
- Routine Description:
- This routine returns the null-terminated path of the controlling terminal
- for the current process. Access to the terminal path returned by this
- function is not guaranteed.
- Arguments:
- Buffer - Supplies an optional pointer to a buffer of at least length
- L_ctermid where the path to the terminal will be returned. If this is
- NULL, static storage will be used and returned, in which case the
- caller should not modify or free the buffer.
- Return Value:
- Returns a pointer to the string containing the path of the controlling
- terminal on success.
- NULL on failure.
- --*/
- {
- if (ClTerminalIdBuffer == NULL) {
- ClTerminalIdBuffer = malloc(L_ctermid);
- if (ClTerminalIdBuffer == NULL) {
- errno = ENOMEM;
- return NULL;
- }
- }
- return ctermid_r(ClTerminalIdBuffer);
- }
- LIBC_API
- char *
- ctermid_r (
- char *Buffer
- )
- /*++
- Routine Description:
- This routine returns the null-terminated path of the controlling terminal
- for the current process.
- Arguments:
- Buffer - Supplies a pointer to a buffer of at least length L_ctermid where
- the path to the terminal will be returned.
- Return Value:
- Returns a pointer to the supplied buffer on success.
- NULL on failure.
- --*/
- {
- if (Buffer == NULL) {
- return NULL;
- }
- snprintf(Buffer, L_ctermid, _PATH_TTY);
- return Buffer;
- }
- LIBC_API
- int
- ioctl (
- int FileDescriptor,
- int Request,
- ...
- )
- /*++
- Routine Description:
- This routine sends an I/O control request to the given file descriptor.
- Arguments:
- FileDescriptor - Supplies the file descriptor to send the control request
- to.
- Request - Supplies the numeric request to send. This is device-specific.
- ... - Supplies a variable number of arguments for historical reasons, but
- this routine expects there to be exactly one more argument, a pointer
- to memory. The size of this memory is request-specific, but can be no
- larger than 4096 bytes. The native version of this routine can specify
- larger values.
- Return Value:
- 0 on success.
- -1 on failure, and errno will be set to contain more information.
- --*/
- {
- void *Argument;
- va_list ArgumentList;
- KSTATUS Status;
- va_start(ArgumentList, Request);
- Argument = va_arg(ArgumentList, void *);
- va_end(ArgumentList);
- Status = OsUserControl((HANDLE)(UINTN)FileDescriptor,
- Request,
- Argument,
- 4096);
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- return 0;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- int
- ClpOpen (
- int Directory,
- const char *Path,
- int OpenFlags,
- va_list ArgumentList
- )
- /*++
- Routine Description:
- This routine opens a file and connects it to a file descriptor.
- Arguments:
- Directory - Supplies an optional file descriptor. If the given path
- is a relative path, the directory referenced by this descriptor will
- be used as a starting point for path resolution. Supply AT_FDCWD to
- use the working directory for relative paths. This is normally the
- expected behavior.
- Path - Supplies a pointer to a null terminated string containing the path
- of the file to open.
- OpenFlags - Supplies a set of flags ORed together. See O_* definitions.
- ArgumentList - Supplies the variadic arguments to the open call.
- Return Value:
- Returns a file descriptor on success.
- -1 on failure. The errno variable will be set to indicate the error.
- --*/
- {
- mode_t CreateMode;
- FILE_PERMISSIONS CreatePermissions;
- HANDLE FileHandle;
- ULONG OsOpenFlags;
- ULONG PathLength;
- KSTATUS Status;
- if (Path == NULL) {
- errno = EINVAL;
- return -1;
- }
- PathLength = RtlStringLength((PSTR)Path) + 1;
- OsOpenFlags = 0;
- CreatePermissions = 0;
- //
- // This assert stands for not just the openat call, but for all the *at
- // calls out there that rely on this assumption.
- //
- assert(INVALID_HANDLE == (HANDLE)AT_FDCWD);
- //
- // Set the access mask.
- //
- switch (OpenFlags & O_ACCMODE) {
- case O_RDONLY:
- OsOpenFlags |= SYS_OPEN_FLAG_READ;
- break;
- case O_WRONLY:
- OsOpenFlags |= SYS_OPEN_FLAG_WRITE;
- break;
- case O_RDWR:
- OsOpenFlags |= SYS_OPEN_FLAG_READ | SYS_OPEN_FLAG_WRITE;
- break;
- default:
- break;
- }
- assert(O_EXEC == O_SEARCH);
- if ((OpenFlags & O_EXEC) != 0) {
- OsOpenFlags |= SYS_OPEN_FLAG_EXECUTE;
- }
- if ((OpenFlags & O_TRUNC) != 0) {
- OsOpenFlags |= SYS_OPEN_FLAG_TRUNCATE;
- }
- if ((OpenFlags & O_APPEND) != 0) {
- OsOpenFlags |= SYS_OPEN_FLAG_APPEND;
- }
- if ((OpenFlags & O_NONBLOCK) != 0) {
- OsOpenFlags |= SYS_OPEN_FLAG_NON_BLOCKING;
- }
- if ((OpenFlags & O_DIRECTORY) != 0) {
- OsOpenFlags |= SYS_OPEN_FLAG_DIRECTORY;
- }
- if ((OpenFlags & O_NOFOLLOW) != 0) {
- OsOpenFlags |= SYS_OPEN_FLAG_NO_SYMBOLIC_LINK;
- }
- if ((OpenFlags & O_NOATIME) != 0) {
- OsOpenFlags |= SYS_OPEN_FLAG_NO_ACCESS_TIME;
- }
- assert((O_SYNC == O_DSYNC) && (O_SYNC == O_RSYNC));
- if ((OpenFlags & O_SYNC) != 0) {
- OsOpenFlags |= SYS_OPEN_FLAG_SYNCHRONIZED;
- }
- if ((OpenFlags & O_NOCTTY) != 0) {
- OsOpenFlags |= SYS_OPEN_FLAG_NO_CONTROLLING_TERMINAL;
- }
- if ((OpenFlags & O_CLOEXEC) != 0) {
- OsOpenFlags |= SYS_OPEN_FLAG_CLOSE_ON_EXECUTE;
- }
- //
- // O_PATH is equivalent to opening with no access.
- //
- if ((OpenFlags & O_PATH) != 0) {
- OsOpenFlags &= ~(SYS_OPEN_FLAG_READ | SYS_OPEN_FLAG_WRITE |
- SYS_OPEN_FLAG_EXECUTE);
- }
- if ((OpenFlags & O_ASYNC) != 0) {
- OsOpenFlags |= SYS_OPEN_FLAG_ASYNCHRONOUS;
- }
- //
- // Set other flags.
- //
- if ((OpenFlags & O_CREAT) != 0) {
- OsOpenFlags |= SYS_OPEN_FLAG_CREATE;
- if ((OpenFlags & O_EXCL) != 0) {
- OsOpenFlags |= SYS_OPEN_FLAG_FAIL_IF_EXISTS;
- }
- CreateMode = va_arg(ArgumentList, mode_t);
- ASSERT_FILE_PERMISSIONS_EQUIVALENT();
- CreatePermissions = CreateMode;
- }
- Status = OsOpen((HANDLE)(UINTN)Directory,
- (PSTR)Path,
- PathLength,
- OsOpenFlags,
- CreatePermissions,
- &FileHandle);
- if (!KSUCCESS(Status)) {
- errno = ClConvertKstatusToErrorNumber(Status);
- return -1;
- }
- return (int)(UINTN)FileHandle;
- }
- BOOL
- ClpAsPrintWriteCharacter (
- INT Character,
- PPRINT_FORMAT_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine writes a character to the output during a printf-style
- formatting operation.
- Arguments:
- Character - Supplies the character to be written.
- Context - Supplies a pointer to the printf-context.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- PASPRINT_CONTEXT AsContext;
- PSTR NewBuffer;
- UINTN NewCapacity;
- AsContext = Context->Context;
- //
- // Reallocate the buffer if needed.
- //
- if (AsContext->Size + 1 >= AsContext->Capacity) {
- NewCapacity = AsContext->Capacity * 2;
- NewBuffer = NULL;
- if (NewCapacity > AsContext->Capacity) {
- NewBuffer = realloc(AsContext->Buffer, NewCapacity);
- }
- if (NewBuffer == NULL) {
- free(AsContext->Buffer);
- AsContext->Buffer = NULL;
- return FALSE;
- }
- AsContext->Buffer = NewBuffer;
- AsContext->Capacity = NewCapacity;
- }
- AsContext->Buffer[AsContext->Size] = Character;
- AsContext->Size += 1;
- return TRUE;
- }
|