123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944 |
- /*
- * fs/cifs/cifssmb.c
- *
- * Copyright (C) International Business Machines Corp., 2002,2005
- * Author(s): Steve French (sfrench@us.ibm.com)
- *
- * Contains the routines for constructing the SMB PDUs themselves
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
- /* These are mostly routines that operate on a pathname, or on a tree id */
- /* (mounted volume), but there are eight handle based routines which must be */
- /* treated slightly different for reconnection purposes since we never want */
- /* to reuse a stale file handle and the caller knows the file handle */
- #include <linux/fs.h>
- #include <linux/kernel.h>
- #include <linux/vfs.h>
- #include <linux/posix_acl_xattr.h>
- #include <asm/uaccess.h>
- #include "cifspdu.h"
- #include "cifsglob.h"
- #include "cifsproto.h"
- #include "cifs_unicode.h"
- #include "cifs_debug.h"
- #include "cifsacl.h"
- #ifdef CONFIG_CIFS_POSIX
- static struct {
- int index;
- char *name;
- } protocols[] = {
- {CIFS_PROT, "\2NT LM 0.12"},
- {CIFS_PROT, "\2POSIX 2"},
- {BAD_PROT, "\2"}
- };
- #else
- static struct {
- int index;
- char *name;
- } protocols[] = {
- {CIFS_PROT, "\2NT LM 0.12"},
- {BAD_PROT, "\2"}
- };
- #endif
- /* Mark as invalid, all open files on tree connections since they
- were closed when session to server was lost */
- static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
- {
- struct cifsFileInfo *open_file = NULL;
- struct list_head * tmp;
- struct list_head * tmp1;
- /* list all files open on tree connection and mark them invalid */
- write_lock(&GlobalSMBSeslock);
- list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
- open_file = list_entry(tmp,struct cifsFileInfo, tlist);
- if(open_file) {
- open_file->invalidHandle = TRUE;
- }
- }
- write_unlock(&GlobalSMBSeslock);
- /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
- to this tcon */
- }
- /* If the return code is zero, this function must fill in request_buf pointer */
- static int
- small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
- void **request_buf /* returned */)
- {
- int rc = 0;
- /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
- check for tcp and smb session status done differently
- for those three - in the calling routine */
- if(tcon) {
- if(tcon->tidStatus == CifsExiting) {
- /* only tree disconnect, open, and write,
- (and ulogoff which does not have tcon)
- are allowed as we start force umount */
- if((smb_command != SMB_COM_WRITE_ANDX) &&
- (smb_command != SMB_COM_OPEN_ANDX) &&
- (smb_command != SMB_COM_TREE_DISCONNECT)) {
- cFYI(1,("can not send cmd %d while umounting",
- smb_command));
- return -ENODEV;
- }
- }
- if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
- (tcon->ses->server)){
- struct nls_table *nls_codepage;
- /* Give Demultiplex thread up to 10 seconds to
- reconnect, should be greater than cifs socket
- timeout which is 7 seconds */
- while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
- wait_event_interruptible_timeout(tcon->ses->server->response_q,
- (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
- if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
- /* on "soft" mounts we wait once */
- if((tcon->retry == FALSE) ||
- (tcon->ses->status == CifsExiting)) {
- cFYI(1,("gave up waiting on reconnect in smb_init"));
- return -EHOSTDOWN;
- } /* else "hard" mount - keep retrying
- until process is killed or server
- comes back on-line */
- } else /* TCP session is reestablished now */
- break;
-
- }
-
- nls_codepage = load_nls_default();
- /* need to prevent multiple threads trying to
- simultaneously reconnect the same SMB session */
- down(&tcon->ses->sesSem);
- if(tcon->ses->status == CifsNeedReconnect)
- rc = cifs_setup_session(0, tcon->ses,
- nls_codepage);
- if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
- mark_open_files_invalid(tcon);
- rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
- , nls_codepage);
- up(&tcon->ses->sesSem);
- /* BB FIXME add code to check if wsize needs
- update due to negotiated smb buffer size
- shrinking */
- if(rc == 0)
- atomic_inc(&tconInfoReconnectCount);
- cFYI(1, ("reconnect tcon rc = %d", rc));
- /* Removed call to reopen open files here -
- it is safer (and faster) to reopen files
- one at a time as needed in read and write */
- /* Check if handle based operation so we
- know whether we can continue or not without
- returning to caller to reset file handle */
- switch(smb_command) {
- case SMB_COM_READ_ANDX:
- case SMB_COM_WRITE_ANDX:
- case SMB_COM_CLOSE:
- case SMB_COM_FIND_CLOSE2:
- case SMB_COM_LOCKING_ANDX: {
- unload_nls(nls_codepage);
- return -EAGAIN;
- }
- }
- } else {
- up(&tcon->ses->sesSem);
- }
- unload_nls(nls_codepage);
- } else {
- return -EIO;
- }
- }
- if(rc)
- return rc;
- *request_buf = cifs_small_buf_get();
- if (*request_buf == NULL) {
- /* BB should we add a retry in here if not a writepage? */
- return -ENOMEM;
- }
- header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
- if(tcon != NULL)
- cifs_stats_inc(&tcon->num_smbs_sent);
- return rc;
- }
- /* If the return code is zero, this function must fill in request_buf pointer */
- static int
- smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
- void **request_buf /* returned */ ,
- void **response_buf /* returned */ )
- {
- int rc = 0;
- /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
- check for tcp and smb session status done differently
- for those three - in the calling routine */
- if(tcon) {
- if(tcon->tidStatus == CifsExiting) {
- /* only tree disconnect, open, and write,
- (and ulogoff which does not have tcon)
- are allowed as we start force umount */
- if((smb_command != SMB_COM_WRITE_ANDX) &&
- (smb_command != SMB_COM_OPEN_ANDX) &&
- (smb_command != SMB_COM_TREE_DISCONNECT)) {
- cFYI(1,("can not send cmd %d while umounting",
- smb_command));
- return -ENODEV;
- }
- }
- if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
- (tcon->ses->server)){
- struct nls_table *nls_codepage;
- /* Give Demultiplex thread up to 10 seconds to
- reconnect, should be greater than cifs socket
- timeout which is 7 seconds */
- while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
- wait_event_interruptible_timeout(tcon->ses->server->response_q,
- (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
- if(tcon->ses->server->tcpStatus ==
- CifsNeedReconnect) {
- /* on "soft" mounts we wait once */
- if((tcon->retry == FALSE) ||
- (tcon->ses->status == CifsExiting)) {
- cFYI(1,("gave up waiting on reconnect in smb_init"));
- return -EHOSTDOWN;
- } /* else "hard" mount - keep retrying
- until process is killed or server
- comes on-line */
- } else /* TCP session is reestablished now */
- break;
-
- }
-
- nls_codepage = load_nls_default();
- /* need to prevent multiple threads trying to
- simultaneously reconnect the same SMB session */
- down(&tcon->ses->sesSem);
- if(tcon->ses->status == CifsNeedReconnect)
- rc = cifs_setup_session(0, tcon->ses,
- nls_codepage);
- if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
- mark_open_files_invalid(tcon);
- rc = CIFSTCon(0, tcon->ses, tcon->treeName,
- tcon, nls_codepage);
- up(&tcon->ses->sesSem);
- /* BB FIXME add code to check if wsize needs
- update due to negotiated smb buffer size
- shrinking */
- if(rc == 0)
- atomic_inc(&tconInfoReconnectCount);
- cFYI(1, ("reconnect tcon rc = %d", rc));
- /* Removed call to reopen open files here -
- it is safer (and faster) to reopen files
- one at a time as needed in read and write */
- /* Check if handle based operation so we
- know whether we can continue or not without
- returning to caller to reset file handle */
- switch(smb_command) {
- case SMB_COM_READ_ANDX:
- case SMB_COM_WRITE_ANDX:
- case SMB_COM_CLOSE:
- case SMB_COM_FIND_CLOSE2:
- case SMB_COM_LOCKING_ANDX: {
- unload_nls(nls_codepage);
- return -EAGAIN;
- }
- }
- } else {
- up(&tcon->ses->sesSem);
- }
- unload_nls(nls_codepage);
- } else {
- return -EIO;
- }
- }
- if(rc)
- return rc;
- *request_buf = cifs_buf_get();
- if (*request_buf == NULL) {
- /* BB should we add a retry in here if not a writepage? */
- return -ENOMEM;
- }
- /* Although the original thought was we needed the response buf for */
- /* potential retries of smb operations it turns out we can determine */
- /* from the mid flags when the request buffer can be resent without */
- /* having to use a second distinct buffer for the response */
- *response_buf = *request_buf;
- header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
- wct /*wct */ );
- if(tcon != NULL)
- cifs_stats_inc(&tcon->num_smbs_sent);
- return rc;
- }
- static int validate_t2(struct smb_t2_rsp * pSMB)
- {
- int rc = -EINVAL;
- int total_size;
- char * pBCC;
- /* check for plausible wct, bcc and t2 data and parm sizes */
- /* check for parm and data offset going beyond end of smb */
- if(pSMB->hdr.WordCount >= 10) {
- if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
- (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
- /* check that bcc is at least as big as parms + data */
- /* check that bcc is less than negotiated smb buffer */
- total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
- if(total_size < 512) {
- total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
- /* BCC le converted in SendReceive */
- pBCC = (pSMB->hdr.WordCount * 2) +
- sizeof(struct smb_hdr) +
- (char *)pSMB;
- if((total_size <= (*(u16 *)pBCC)) &&
- (total_size <
- CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
- return 0;
- }
-
- }
- }
- }
- cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
- sizeof(struct smb_t2_rsp) + 16);
- return rc;
- }
- int
- CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
- {
- NEGOTIATE_REQ *pSMB;
- NEGOTIATE_RSP *pSMBr;
- int rc = 0;
- int bytes_returned;
- struct TCP_Server_Info * server;
- u16 count;
- if(ses->server)
- server = ses->server;
- else {
- rc = -EIO;
- return rc;
- }
- rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
- (void **) &pSMB, (void **) &pSMBr);
- if (rc)
- return rc;
- pSMB->hdr.Mid = GetNextMid(server);
- pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
- if (extended_security)
- pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
- count = strlen(protocols[0].name) + 1;
- strncpy(pSMB->DialectsArray, protocols[0].name, 30);
- /* null guaranteed to be at end of source and target buffers anyway */
- pSMB->hdr.smb_buf_length += count;
- pSMB->ByteCount = cpu_to_le16(count);
- rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc == 0) {
- server->secMode = pSMBr->SecurityMode;
- if((server->secMode & SECMODE_USER) == 0)
- cFYI(1,("share mode security"));
- server->secType = NTLM; /* BB override default for
- NTLMv2 or kerberos v5 */
- /* one byte - no need to convert this or EncryptionKeyLen
- from little endian */
- server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
- /* probably no need to store and check maxvcs */
- server->maxBuf =
- min(le32_to_cpu(pSMBr->MaxBufferSize),
- (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
- server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
- cFYI(0, ("Max buf = %d", ses->server->maxBuf));
- GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
- server->capabilities = le32_to_cpu(pSMBr->Capabilities);
- server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
- /* BB with UTC do we ever need to be using srvr timezone? */
- if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
- memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
- CIFS_CRYPTO_KEY_SIZE);
- } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
- && (pSMBr->EncryptionKeyLength == 0)) {
- /* decode security blob */
- } else
- rc = -EIO;
- /* BB might be helpful to save off the domain of server here */
- if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
- (server->capabilities & CAP_EXTENDED_SECURITY)) {
- count = pSMBr->ByteCount;
- if (count < 16)
- rc = -EIO;
- else if (count == 16) {
- server->secType = RawNTLMSSP;
- if (server->socketUseCount.counter > 1) {
- if (memcmp
- (server->server_GUID,
- pSMBr->u.extended_response.
- GUID, 16) != 0) {
- cFYI(1, ("server UID changed"));
- memcpy(server->
- server_GUID,
- pSMBr->u.
- extended_response.
- GUID, 16);
- }
- } else
- memcpy(server->server_GUID,
- pSMBr->u.extended_response.
- GUID, 16);
- } else {
- rc = decode_negTokenInit(pSMBr->u.
- extended_response.
- SecurityBlob,
- count - 16,
- &server->secType);
- if(rc == 1) {
- /* BB Need to fill struct for sessetup here */
- rc = -EOPNOTSUPP;
- } else {
- rc = -EINVAL;
- }
- }
- } else
- server->capabilities &= ~CAP_EXTENDED_SECURITY;
- if(sign_CIFS_PDUs == FALSE) {
- if(server->secMode & SECMODE_SIGN_REQUIRED)
- cERROR(1,
- ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
- server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
- } else if(sign_CIFS_PDUs == 1) {
- if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
- server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
- }
-
- }
-
- cifs_buf_release(pSMB);
- return rc;
- }
- int
- CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
- {
- struct smb_hdr *smb_buffer;
- struct smb_hdr *smb_buffer_response; /* BB removeme BB */
- int rc = 0;
- int length;
- cFYI(1, ("In tree disconnect"));
- /*
- * If last user of the connection and
- * connection alive - disconnect it
- * If this is the last connection on the server session disconnect it
- * (and inside session disconnect we should check if tcp socket needs
- * to be freed and kernel thread woken up).
- */
- if (tcon)
- down(&tcon->tconSem);
- else
- return -EIO;
- atomic_dec(&tcon->useCount);
- if (atomic_read(&tcon->useCount) > 0) {
- up(&tcon->tconSem);
- return -EBUSY;
- }
- /* No need to return error on this operation if tid invalidated and
- closed on server already e.g. due to tcp session crashing */
- if(tcon->tidStatus == CifsNeedReconnect) {
- up(&tcon->tconSem);
- return 0;
- }
- if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
- up(&tcon->tconSem);
- return -EIO;
- }
- rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
- (void **)&smb_buffer);
- if (rc) {
- up(&tcon->tconSem);
- return rc;
- } else {
- smb_buffer_response = smb_buffer; /* BB removeme BB */
- }
- rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
- &length, 0);
- if (rc)
- cFYI(1, ("Tree disconnect failed %d", rc));
- if (smb_buffer)
- cifs_small_buf_release(smb_buffer);
- up(&tcon->tconSem);
- /* No need to return error on this operation if tid invalidated and
- closed on server already e.g. due to tcp session crashing */
- if (rc == -EAGAIN)
- rc = 0;
- return rc;
- }
- int
- CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
- {
- struct smb_hdr *smb_buffer_response;
- LOGOFF_ANDX_REQ *pSMB;
- int rc = 0;
- int length;
- cFYI(1, ("In SMBLogoff for session disconnect"));
- if (ses)
- down(&ses->sesSem);
- else
- return -EIO;
- atomic_dec(&ses->inUse);
- if (atomic_read(&ses->inUse) > 0) {
- up(&ses->sesSem);
- return -EBUSY;
- }
- rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
- if (rc) {
- up(&ses->sesSem);
- return rc;
- }
- smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
-
- if(ses->server) {
- pSMB->hdr.Mid = GetNextMid(ses->server);
- if(ses->server->secMode &
- (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
- pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
- }
- pSMB->hdr.Uid = ses->Suid;
- pSMB->AndXCommand = 0xFF;
- rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
- smb_buffer_response, &length, 0);
- if (ses->server) {
- atomic_dec(&ses->server->socketUseCount);
- if (atomic_read(&ses->server->socketUseCount) == 0) {
- spin_lock(&GlobalMid_Lock);
- ses->server->tcpStatus = CifsExiting;
- spin_unlock(&GlobalMid_Lock);
- rc = -ESHUTDOWN;
- }
- }
- up(&ses->sesSem);
- cifs_small_buf_release(pSMB);
- /* if session dead then we do not need to do ulogoff,
- since server closed smb session, no sense reporting
- error */
- if (rc == -EAGAIN)
- rc = 0;
- return rc;
- }
- int
- CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
- const struct nls_table *nls_codepage, int remap)
- {
- DELETE_FILE_REQ *pSMB = NULL;
- DELETE_FILE_RSP *pSMBr = NULL;
- int rc = 0;
- int bytes_returned;
- int name_len;
- DelFileRetry:
- rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve check for buffer overruns BB */
- name_len = strnlen(fileName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->fileName, fileName, name_len);
- }
- pSMB->SearchAttributes =
- cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
- pSMB->BufferFormat = 0x04;
- pSMB->hdr.smb_buf_length += name_len + 1;
- pSMB->ByteCount = cpu_to_le16(name_len + 1);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_deletes);
- if (rc) {
- cFYI(1, ("Error in RMFile = %d", rc));
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto DelFileRetry;
- return rc;
- }
- int
- CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
- const struct nls_table *nls_codepage, int remap)
- {
- DELETE_DIRECTORY_REQ *pSMB = NULL;
- DELETE_DIRECTORY_RSP *pSMBr = NULL;
- int rc = 0;
- int bytes_returned;
- int name_len;
- cFYI(1, ("In CIFSSMBRmDir"));
- RmDirRetry:
- rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve check for buffer overruns BB */
- name_len = strnlen(dirName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->DirName, dirName, name_len);
- }
- pSMB->BufferFormat = 0x04;
- pSMB->hdr.smb_buf_length += name_len + 1;
- pSMB->ByteCount = cpu_to_le16(name_len + 1);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_rmdirs);
- if (rc) {
- cFYI(1, ("Error in RMDir = %d", rc));
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto RmDirRetry;
- return rc;
- }
- int
- CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
- const char *name, const struct nls_table *nls_codepage, int remap)
- {
- int rc = 0;
- CREATE_DIRECTORY_REQ *pSMB = NULL;
- CREATE_DIRECTORY_RSP *pSMBr = NULL;
- int bytes_returned;
- int name_len;
- cFYI(1, ("In CIFSSMBMkDir"));
- MkDirRetry:
- rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve check for buffer overruns BB */
- name_len = strnlen(name, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->DirName, name, name_len);
- }
- pSMB->BufferFormat = 0x04;
- pSMB->hdr.smb_buf_length += name_len + 1;
- pSMB->ByteCount = cpu_to_le16(name_len + 1);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_mkdirs);
- if (rc) {
- cFYI(1, ("Error in Mkdir = %d", rc));
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto MkDirRetry;
- return rc;
- }
- static __u16 convert_disposition(int disposition)
- {
- __u16 ofun = 0;
- switch (disposition) {
- case FILE_SUPERSEDE:
- ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
- break;
- case FILE_OPEN:
- ofun = SMBOPEN_OAPPEND;
- break;
- case FILE_CREATE:
- ofun = SMBOPEN_OCREATE;
- break;
- case FILE_OPEN_IF:
- ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
- break;
- case FILE_OVERWRITE:
- ofun = SMBOPEN_OTRUNC;
- break;
- case FILE_OVERWRITE_IF:
- ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
- break;
- default:
- cFYI(1,("unknown disposition %d",disposition));
- ofun = SMBOPEN_OAPPEND; /* regular open */
- }
- return ofun;
- }
- int
- SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
- const char *fileName, const int openDisposition,
- const int access_flags, const int create_options, __u16 * netfid,
- int *pOplock, FILE_ALL_INFO * pfile_info,
- const struct nls_table *nls_codepage, int remap)
- {
- int rc = -EACCES;
- OPENX_REQ *pSMB = NULL;
- OPENX_RSP *pSMBr = NULL;
- int bytes_returned;
- int name_len;
- __u16 count;
- OldOpenRetry:
- rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- pSMB->AndXCommand = 0xFF; /* none */
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- count = 1; /* account for one byte pad to word boundary */
- name_len =
- cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
- fileName, PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve check for buffer overruns BB */
- count = 0; /* no pad */
- name_len = strnlen(fileName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->fileName, fileName, name_len);
- }
- if (*pOplock & REQ_OPLOCK)
- pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
- else if (*pOplock & REQ_BATCHOPLOCK) {
- pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
- }
- pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
- /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
- /* 0 = read
- 1 = write
- 2 = rw
- 3 = execute
- */
- pSMB->Mode = cpu_to_le16(2);
- pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
- /* set file as system file if special file such
- as fifo and server expecting SFU style and
- no Unix extensions */
- if(create_options & CREATE_OPTION_SPECIAL)
- pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
- else
- pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
- /* if ((omode & S_IWUGO) == 0)
- pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
- /* Above line causes problems due to vfs splitting create into two
- pieces - need to set mode after file created not while it is
- being created */
- /* BB FIXME BB */
- /* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
- /* BB FIXME END BB */
- pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
- pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
- count += name_len;
- pSMB->hdr.smb_buf_length += count;
- pSMB->ByteCount = cpu_to_le16(count);
- /* long_op set to 1 to allow for oplock break timeouts */
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 1);
- cifs_stats_inc(&tcon->num_opens);
- if (rc) {
- cFYI(1, ("Error in Open = %d", rc));
- } else {
- /* BB verify if wct == 15 */
- /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
- *netfid = pSMBr->Fid; /* cifs fid stays in le */
- /* Let caller know file was created so we can set the mode. */
- /* Do we care about the CreateAction in any other cases? */
- /* BB FIXME BB */
- /* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
- *pOplock |= CIFS_CREATE_ACTION; */
- /* BB FIXME END */
- if(pfile_info) {
- pfile_info->CreationTime = 0; /* BB convert CreateTime*/
- pfile_info->LastAccessTime = 0; /* BB fixme */
- pfile_info->LastWriteTime = 0; /* BB fixme */
- pfile_info->ChangeTime = 0; /* BB fixme */
- pfile_info->Attributes =
- cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
- /* the file_info buf is endian converted by caller */
- pfile_info->AllocationSize =
- cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
- pfile_info->EndOfFile = pfile_info->AllocationSize;
- pfile_info->NumberOfLinks = cpu_to_le32(1);
- }
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto OldOpenRetry;
- return rc;
- }
- int
- CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
- const char *fileName, const int openDisposition,
- const int access_flags, const int create_options, __u16 * netfid,
- int *pOplock, FILE_ALL_INFO * pfile_info,
- const struct nls_table *nls_codepage, int remap)
- {
- int rc = -EACCES;
- OPEN_REQ *pSMB = NULL;
- OPEN_RSP *pSMBr = NULL;
- int bytes_returned;
- int name_len;
- __u16 count;
- openRetry:
- rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- pSMB->AndXCommand = 0xFF; /* none */
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- count = 1; /* account for one byte pad to word boundary */
- name_len =
- cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
- fileName, PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- pSMB->NameLength = cpu_to_le16(name_len);
- } else { /* BB improve check for buffer overruns BB */
- count = 0; /* no pad */
- name_len = strnlen(fileName, PATH_MAX);
- name_len++; /* trailing null */
- pSMB->NameLength = cpu_to_le16(name_len);
- strncpy(pSMB->fileName, fileName, name_len);
- }
- if (*pOplock & REQ_OPLOCK)
- pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
- else if (*pOplock & REQ_BATCHOPLOCK) {
- pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
- }
- pSMB->DesiredAccess = cpu_to_le32(access_flags);
- pSMB->AllocationSize = 0;
- /* set file as system file if special file such
- as fifo and server expecting SFU style and
- no Unix extensions */
- if(create_options & CREATE_OPTION_SPECIAL)
- pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
- else
- pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
- /* XP does not handle ATTR_POSIX_SEMANTICS */
- /* but it helps speed up case sensitive checks for other
- servers such as Samba */
- if (tcon->ses->capabilities & CAP_UNIX)
- pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
- /* if ((omode & S_IWUGO) == 0)
- pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
- /* Above line causes problems due to vfs splitting create into two
- pieces - need to set mode after file created not while it is
- being created */
- pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
- pSMB->CreateDisposition = cpu_to_le32(openDisposition);
- pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
- /* BB Expirement with various impersonation levels and verify */
- pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
- pSMB->SecurityFlags =
- SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
- count += name_len;
- pSMB->hdr.smb_buf_length += count;
- pSMB->ByteCount = cpu_to_le16(count);
- /* long_op set to 1 to allow for oplock break timeouts */
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 1);
- cifs_stats_inc(&tcon->num_opens);
- if (rc) {
- cFYI(1, ("Error in Open = %d", rc));
- } else {
- *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
- *netfid = pSMBr->Fid; /* cifs fid stays in le */
- /* Let caller know file was created so we can set the mode. */
- /* Do we care about the CreateAction in any other cases? */
- if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
- *pOplock |= CIFS_CREATE_ACTION;
- if(pfile_info) {
- memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
- 36 /* CreationTime to Attributes */);
- /* the file_info buf is endian converted by caller */
- pfile_info->AllocationSize = pSMBr->AllocationSize;
- pfile_info->EndOfFile = pSMBr->EndOfFile;
- pfile_info->NumberOfLinks = cpu_to_le32(1);
- }
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto openRetry;
- return rc;
- }
- int
- CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
- const int netfid, const unsigned int count,
- const __u64 lseek, unsigned int *nbytes, char **buf,
- int * pbuf_type)
- {
- int rc = -EACCES;
- READ_REQ *pSMB = NULL;
- READ_RSP *pSMBr = NULL;
- char *pReadData = NULL;
- int wct;
- int resp_buf_type = 0;
- struct kvec iov[1];
- cFYI(1,("Reading %d bytes on fid %d",count,netfid));
- if(tcon->ses->capabilities & CAP_LARGE_FILES)
- wct = 12;
- else
- wct = 10; /* old style read */
- *nbytes = 0;
- rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
- if (rc)
- return rc;
- /* tcon and ses pointer are checked in smb_init */
- if (tcon->ses->server == NULL)
- return -ECONNABORTED;
- pSMB->AndXCommand = 0xFF; /* none */
- pSMB->Fid = netfid;
- pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
- if(wct == 12)
- pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
- else if((lseek >> 32) > 0) /* can not handle this big offset for old */
- return -EIO;
- pSMB->Remaining = 0;
- pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
- pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
- if(wct == 12)
- pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
- else {
- /* old style read */
- struct smb_com_readx_req * pSMBW =
- (struct smb_com_readx_req *)pSMB;
- pSMBW->ByteCount = 0;
- }
- iov[0].iov_base = (char *)pSMB;
- iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
- rc = SendReceive2(xid, tcon->ses, iov,
- 1 /* num iovecs */,
- &resp_buf_type, 0);
- cifs_stats_inc(&tcon->num_reads);
- pSMBr = (READ_RSP *)iov[0].iov_base;
- if (rc) {
- cERROR(1, ("Send error in read = %d", rc));
- } else {
- int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
- data_length = data_length << 16;
- data_length += le16_to_cpu(pSMBr->DataLength);
- *nbytes = data_length;
- /*check that DataLength would not go beyond end of SMB */
- if ((data_length > CIFSMaxBufSize)
- || (data_length > count)) {
- cFYI(1,("bad length %d for count %d",data_length,count));
- rc = -EIO;
- *nbytes = 0;
- } else {
- pReadData = (char *) (&pSMBr->hdr.Protocol) +
- le16_to_cpu(pSMBr->DataOffset);
- /* if(rc = copy_to_user(buf, pReadData, data_length)) {
- cERROR(1,("Faulting on read rc = %d",rc));
- rc = -EFAULT;
- }*/ /* can not use copy_to_user when using page cache*/
- if(*buf)
- memcpy(*buf,pReadData,data_length);
- }
- }
- cifs_small_buf_release(pSMB);
- if(*buf) {
- if(resp_buf_type == CIFS_SMALL_BUFFER)
- cifs_small_buf_release(iov[0].iov_base);
- else if(resp_buf_type == CIFS_LARGE_BUFFER)
- cifs_buf_release(iov[0].iov_base);
- } else /* return buffer to caller to free */ /* BB FIXME how do we tell caller if it is not a large buffer */ {
- *buf = iov[0].iov_base;
- if(resp_buf_type == CIFS_SMALL_BUFFER)
- *pbuf_type = CIFS_SMALL_BUFFER;
- else if(resp_buf_type == CIFS_LARGE_BUFFER)
- *pbuf_type = CIFS_LARGE_BUFFER;
- }
- /* Note: On -EAGAIN error only caller can retry on handle based calls
- since file handle passed in no longer valid */
- return rc;
- }
- int
- CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
- const int netfid, const unsigned int count,
- const __u64 offset, unsigned int *nbytes, const char *buf,
- const char __user * ubuf, const int long_op)
- {
- int rc = -EACCES;
- WRITE_REQ *pSMB = NULL;
- WRITE_RSP *pSMBr = NULL;
- int bytes_returned, wct;
- __u32 bytes_sent;
- __u16 byte_count;
- /* cFYI(1,("write at %lld %d bytes",offset,count));*/
- if(tcon->ses == NULL)
- return -ECONNABORTED;
- if(tcon->ses->capabilities & CAP_LARGE_FILES)
- wct = 14;
- else
- wct = 12;
- rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- /* tcon and ses pointer are checked in smb_init */
- if (tcon->ses->server == NULL)
- return -ECONNABORTED;
- pSMB->AndXCommand = 0xFF; /* none */
- pSMB->Fid = netfid;
- pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
- if(wct == 14)
- pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
- else if((offset >> 32) > 0) /* can not handle this big offset for old */
- return -EIO;
-
- pSMB->Reserved = 0xFFFFFFFF;
- pSMB->WriteMode = 0;
- pSMB->Remaining = 0;
- /* Can increase buffer size if buffer is big enough in some cases - ie we
- can send more if LARGE_WRITE_X capability returned by the server and if
- our buffer is big enough or if we convert to iovecs on socket writes
- and eliminate the copy to the CIFS buffer */
- if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
- bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
- } else {
- bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
- & ~0xFF;
- }
- if (bytes_sent > count)
- bytes_sent = count;
- pSMB->DataOffset =
- cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
- if(buf)
- memcpy(pSMB->Data,buf,bytes_sent);
- else if(ubuf) {
- if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
- cifs_buf_release(pSMB);
- return -EFAULT;
- }
- } else if (count != 0) {
- /* No buffer */
- cifs_buf_release(pSMB);
- return -EINVAL;
- } /* else setting file size with write of zero bytes */
- if(wct == 14)
- byte_count = bytes_sent + 1; /* pad */
- else /* wct == 12 */ {
- byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
- }
- pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
- pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
- pSMB->hdr.smb_buf_length += byte_count;
- if(wct == 14)
- pSMB->ByteCount = cpu_to_le16(byte_count);
- else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
- struct smb_com_writex_req * pSMBW =
- (struct smb_com_writex_req *)pSMB;
- pSMBW->ByteCount = cpu_to_le16(byte_count);
- }
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
- cifs_stats_inc(&tcon->num_writes);
- if (rc) {
- cFYI(1, ("Send error in write = %d", rc));
- *nbytes = 0;
- } else {
- *nbytes = le16_to_cpu(pSMBr->CountHigh);
- *nbytes = (*nbytes) << 16;
- *nbytes += le16_to_cpu(pSMBr->Count);
- }
- cifs_buf_release(pSMB);
- /* Note: On -EAGAIN error only caller can retry on handle based calls
- since file handle passed in no longer valid */
- return rc;
- }
- int
- CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
- const int netfid, const unsigned int count,
- const __u64 offset, unsigned int *nbytes, struct kvec *iov,
- int n_vec, const int long_op)
- {
- int rc = -EACCES;
- WRITE_REQ *pSMB = NULL;
- int wct;
- int smb_hdr_len;
- int resp_buf_type = 0;
- cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
- if(tcon->ses->capabilities & CAP_LARGE_FILES)
- wct = 14;
- else
- wct = 12;
- rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
- if (rc)
- return rc;
- /* tcon and ses pointer are checked in smb_init */
- if (tcon->ses->server == NULL)
- return -ECONNABORTED;
- pSMB->AndXCommand = 0xFF; /* none */
- pSMB->Fid = netfid;
- pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
- if(wct == 14)
- pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
- else if((offset >> 32) > 0) /* can not handle this big offset for old */
- return -EIO;
- pSMB->Reserved = 0xFFFFFFFF;
- pSMB->WriteMode = 0;
- pSMB->Remaining = 0;
- pSMB->DataOffset =
- cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
- pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
- pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
- smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
- if(wct == 14)
- pSMB->hdr.smb_buf_length += count+1;
- else /* wct == 12 */
- pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
- if(wct == 14)
- pSMB->ByteCount = cpu_to_le16(count + 1);
- else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
- struct smb_com_writex_req * pSMBW =
- (struct smb_com_writex_req *)pSMB;
- pSMBW->ByteCount = cpu_to_le16(count + 5);
- }
- iov[0].iov_base = pSMB;
- if(wct == 14)
- iov[0].iov_len = smb_hdr_len + 4;
- else /* wct == 12 pad bigger by four bytes */
- iov[0].iov_len = smb_hdr_len + 8;
-
- rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
- long_op);
- cifs_stats_inc(&tcon->num_writes);
- if (rc) {
- cFYI(1, ("Send error Write2 = %d", rc));
- *nbytes = 0;
- } else if(resp_buf_type == 0) {
- /* presumably this can not happen, but best to be safe */
- rc = -EIO;
- *nbytes = 0;
- } else {
- WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
- *nbytes = le16_to_cpu(pSMBr->CountHigh);
- *nbytes = (*nbytes) << 16;
- *nbytes += le16_to_cpu(pSMBr->Count);
- }
- cifs_small_buf_release(pSMB);
- if(resp_buf_type == CIFS_SMALL_BUFFER)
- cifs_small_buf_release(iov[0].iov_base);
- else if(resp_buf_type == CIFS_LARGE_BUFFER)
- cifs_buf_release(iov[0].iov_base);
- /* Note: On -EAGAIN error only caller can retry on handle based calls
- since file handle passed in no longer valid */
- return rc;
- }
- int
- CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
- const __u16 smb_file_id, const __u64 len,
- const __u64 offset, const __u32 numUnlock,
- const __u32 numLock, const __u8 lockType, const int waitFlag)
- {
- int rc = 0;
- LOCK_REQ *pSMB = NULL;
- LOCK_RSP *pSMBr = NULL;
- int bytes_returned;
- int timeout = 0;
- __u16 count;
- cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
- rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
- if (rc)
- return rc;
- pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
- if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
- timeout = -1; /* no response expected */
- pSMB->Timeout = 0;
- } else if (waitFlag == TRUE) {
- timeout = 3; /* blocking operation, no timeout */
- pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
- } else {
- pSMB->Timeout = 0;
- }
- pSMB->NumberOfLocks = cpu_to_le16(numLock);
- pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
- pSMB->LockType = lockType;
- pSMB->AndXCommand = 0xFF; /* none */
- pSMB->Fid = smb_file_id; /* netfid stays le */
- if((numLock != 0) || (numUnlock != 0)) {
- pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
- /* BB where to store pid high? */
- pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
- pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
- pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
- pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
- count = sizeof(LOCKING_ANDX_RANGE);
- } else {
- /* oplock break */
- count = 0;
- }
- pSMB->hdr.smb_buf_length += count;
- pSMB->ByteCount = cpu_to_le16(count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
- cifs_stats_inc(&tcon->num_locks);
- if (rc) {
- cFYI(1, ("Send error in Lock = %d", rc));
- }
- cifs_small_buf_release(pSMB);
- /* Note: On -EAGAIN error only caller can retry on handle based calls
- since file handle passed in no longer valid */
- return rc;
- }
- int
- CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
- {
- int rc = 0;
- CLOSE_REQ *pSMB = NULL;
- CLOSE_RSP *pSMBr = NULL;
- int bytes_returned;
- cFYI(1, ("In CIFSSMBClose"));
- /* do not retry on dead session on close */
- rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
- if(rc == -EAGAIN)
- return 0;
- if (rc)
- return rc;
- pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
- pSMB->FileID = (__u16) smb_file_id;
- pSMB->LastWriteTime = 0;
- pSMB->ByteCount = 0;
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_closes);
- if (rc) {
- if(rc!=-EINTR) {
- /* EINTR is expected when user ctl-c to kill app */
- cERROR(1, ("Send error in Close = %d", rc));
- }
- }
- cifs_small_buf_release(pSMB);
- /* Since session is dead, file will be closed on server already */
- if(rc == -EAGAIN)
- rc = 0;
- return rc;
- }
- int
- CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
- const char *fromName, const char *toName,
- const struct nls_table *nls_codepage, int remap)
- {
- int rc = 0;
- RENAME_REQ *pSMB = NULL;
- RENAME_RSP *pSMBr = NULL;
- int bytes_returned;
- int name_len, name_len2;
- __u16 count;
- cFYI(1, ("In CIFSSMBRename"));
- renameRetry:
- rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- pSMB->BufferFormat = 0x04;
- pSMB->SearchAttributes =
- cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
- ATTR_DIRECTORY);
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- pSMB->OldFileName[name_len] = 0x04; /* pad */
- /* protocol requires ASCII signature byte on Unicode string */
- pSMB->OldFileName[name_len + 1] = 0x00;
- name_len2 =
- cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
- toName, PATH_MAX, nls_codepage, remap);
- name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
- name_len2 *= 2; /* convert to bytes */
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(fromName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->OldFileName, fromName, name_len);
- name_len2 = strnlen(toName, PATH_MAX);
- name_len2++; /* trailing null */
- pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
- strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
- name_len2++; /* trailing null */
- name_len2++; /* signature byte */
- }
- count = 1 /* 1st signature byte */ + name_len + name_len2;
- pSMB->hdr.smb_buf_length += count;
- pSMB->ByteCount = cpu_to_le16(count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_renames);
- if (rc) {
- cFYI(1, ("Send error in rename = %d", rc));
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto renameRetry;
- return rc;
- }
- int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
- int netfid, char * target_name,
- const struct nls_table * nls_codepage, int remap)
- {
- struct smb_com_transaction2_sfi_req *pSMB = NULL;
- struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
- struct set_file_rename * rename_info;
- char *data_offset;
- char dummy_string[30];
- int rc = 0;
- int bytes_returned = 0;
- int len_of_str;
- __u16 params, param_offset, offset, count, byte_count;
- cFYI(1, ("Rename to File by handle"));
- rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- params = 6;
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
- offset = param_offset + params;
- data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
- rename_info = (struct set_file_rename *) data_offset;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
- byte_count = 3 /* pad */ + params;
- pSMB->ParameterCount = cpu_to_le16(params);
- pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->ParameterOffset = cpu_to_le16(param_offset);
- pSMB->DataOffset = cpu_to_le16(offset);
- /* construct random name ".cifs_tmp<inodenum><mid>" */
- rename_info->overwrite = cpu_to_le32(1);
- rename_info->root_fid = 0;
- /* unicode only call */
- if(target_name == NULL) {
- sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
- len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
- dummy_string, 24, nls_codepage, remap);
- } else {
- len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
- target_name, PATH_MAX, nls_codepage, remap);
- }
- rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
- count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
- byte_count += count;
- pSMB->DataCount = cpu_to_le16(count);
- pSMB->TotalDataCount = pSMB->DataCount;
- pSMB->Fid = netfid;
- pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&pTcon->num_t2renames);
- if (rc) {
- cFYI(1,("Send error in Rename (by file handle) = %d", rc));
- }
- cifs_buf_release(pSMB);
- /* Note: On -EAGAIN error only caller can retry on handle based calls
- since file handle passed in no longer valid */
- return rc;
- }
- int
- CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
- const __u16 target_tid, const char *toName, const int flags,
- const struct nls_table *nls_codepage, int remap)
- {
- int rc = 0;
- COPY_REQ *pSMB = NULL;
- COPY_RSP *pSMBr = NULL;
- int bytes_returned;
- int name_len, name_len2;
- __u16 count;
- cFYI(1, ("In CIFSSMBCopy"));
- copyRetry:
- rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- pSMB->BufferFormat = 0x04;
- pSMB->Tid2 = target_tid;
- pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
- fromName, PATH_MAX, nls_codepage,
- remap);
- name_len++; /* trailing null */
- name_len *= 2;
- pSMB->OldFileName[name_len] = 0x04; /* pad */
- /* protocol requires ASCII signature byte on Unicode string */
- pSMB->OldFileName[name_len + 1] = 0x00;
- name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
- toName, PATH_MAX, nls_codepage, remap);
- name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
- name_len2 *= 2; /* convert to bytes */
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(fromName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->OldFileName, fromName, name_len);
- name_len2 = strnlen(toName, PATH_MAX);
- name_len2++; /* trailing null */
- pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
- strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
- name_len2++; /* trailing null */
- name_len2++; /* signature byte */
- }
- count = 1 /* 1st signature byte */ + name_len + name_len2;
- pSMB->hdr.smb_buf_length += count;
- pSMB->ByteCount = cpu_to_le16(count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Send error in copy = %d with %d files copied",
- rc, le16_to_cpu(pSMBr->CopyCount)));
- }
- if (pSMB)
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto copyRetry;
- return rc;
- }
- int
- CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
- const char *fromName, const char *toName,
- const struct nls_table *nls_codepage)
- {
- TRANSACTION2_SPI_REQ *pSMB = NULL;
- TRANSACTION2_SPI_RSP *pSMBr = NULL;
- char *data_offset;
- int name_len;
- int name_len_target;
- int rc = 0;
- int bytes_returned = 0;
- __u16 params, param_offset, offset, byte_count;
- cFYI(1, ("In Symlink Unix style"));
- createSymLinkRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(fromName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, fromName, name_len);
- }
- params = 6 + name_len;
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
- offset = param_offset + params;
- data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len_target =
- cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
- name_len_target++; /* trailing null */
- name_len_target *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len_target = strnlen(toName, PATH_MAX);
- name_len_target++; /* trailing null */
- strncpy(data_offset, toName, name_len_target);
- }
- pSMB->MaxParameterCount = cpu_to_le16(2);
- /* BB find exact max on data count below from sess */
- pSMB->MaxDataCount = cpu_to_le16(1000);
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
- byte_count = 3 /* pad */ + params + name_len_target;
- pSMB->DataCount = cpu_to_le16(name_len_target);
- pSMB->ParameterCount = cpu_to_le16(params);
- pSMB->TotalDataCount = pSMB->DataCount;
- pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->ParameterOffset = cpu_to_le16(param_offset);
- pSMB->DataOffset = cpu_to_le16(offset);
- pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_symlinks);
- if (rc) {
- cFYI(1,
- ("Send error in SetPathInfo (create symlink) = %d",
- rc));
- }
- if (pSMB)
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto createSymLinkRetry;
- return rc;
- }
- int
- CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
- const char *fromName, const char *toName,
- const struct nls_table *nls_codepage, int remap)
- {
- TRANSACTION2_SPI_REQ *pSMB = NULL;
- TRANSACTION2_SPI_RSP *pSMBr = NULL;
- char *data_offset;
- int name_len;
- int name_len_target;
- int rc = 0;
- int bytes_returned = 0;
- __u16 params, param_offset, offset, byte_count;
- cFYI(1, ("In Create Hard link Unix style"));
- createHardLinkRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(toName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, toName, name_len);
- }
- params = 6 + name_len;
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
- offset = param_offset + params;
- data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len_target =
- cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
- nls_codepage, remap);
- name_len_target++; /* trailing null */
- name_len_target *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len_target = strnlen(fromName, PATH_MAX);
- name_len_target++; /* trailing null */
- strncpy(data_offset, fromName, name_len_target);
- }
- pSMB->MaxParameterCount = cpu_to_le16(2);
- /* BB find exact max on data count below from sess*/
- pSMB->MaxDataCount = cpu_to_le16(1000);
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
- byte_count = 3 /* pad */ + params + name_len_target;
- pSMB->ParameterCount = cpu_to_le16(params);
- pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->DataCount = cpu_to_le16(name_len_target);
- pSMB->TotalDataCount = pSMB->DataCount;
- pSMB->ParameterOffset = cpu_to_le16(param_offset);
- pSMB->DataOffset = cpu_to_le16(offset);
- pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_hardlinks);
- if (rc) {
- cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto createHardLinkRetry;
- return rc;
- }
- int
- CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
- const char *fromName, const char *toName,
- const struct nls_table *nls_codepage, int remap)
- {
- int rc = 0;
- NT_RENAME_REQ *pSMB = NULL;
- RENAME_RSP *pSMBr = NULL;
- int bytes_returned;
- int name_len, name_len2;
- __u16 count;
- cFYI(1, ("In CIFSCreateHardLink"));
- winCreateHardLinkRetry:
- rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- pSMB->SearchAttributes =
- cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
- ATTR_DIRECTORY);
- pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
- pSMB->ClusterCount = 0;
- pSMB->BufferFormat = 0x04;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- pSMB->OldFileName[name_len] = 0; /* pad */
- pSMB->OldFileName[name_len + 1] = 0x04;
- name_len2 =
- cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
- toName, PATH_MAX, nls_codepage, remap);
- name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
- name_len2 *= 2; /* convert to bytes */
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(fromName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->OldFileName, fromName, name_len);
- name_len2 = strnlen(toName, PATH_MAX);
- name_len2++; /* trailing null */
- pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
- strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
- name_len2++; /* trailing null */
- name_len2++; /* signature byte */
- }
- count = 1 /* string type byte */ + name_len + name_len2;
- pSMB->hdr.smb_buf_length += count;
- pSMB->ByteCount = cpu_to_le16(count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_hardlinks);
- if (rc) {
- cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto winCreateHardLinkRetry;
- return rc;
- }
- int
- CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *searchName,
- char *symlinkinfo, const int buflen,
- const struct nls_table *nls_codepage)
- {
- /* SMB_QUERY_FILE_UNIX_LINK */
- TRANSACTION2_QPI_REQ *pSMB = NULL;
- TRANSACTION2_QPI_RSP *pSMBr = NULL;
- int rc = 0;
- int bytes_returned;
- int name_len;
- __u16 params, byte_count;
- cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
- querySymLinkRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(searchName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, searchName, name_len);
- }
- params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
- pSMB->TotalDataCount = 0;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- /* BB find exact max data count below from sess structure BB */
- pSMB->MaxDataCount = cpu_to_le16(4000);
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
- byte_count = params + 1 /* pad */ ;
- pSMB->TotalParameterCount = cpu_to_le16(params);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
- } else {
- /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 2))
- /* BB also check enough total bytes returned */
- rc = -EIO; /* bad smb */
- else {
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
- if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len = UniStrnlen((wchar_t *) ((char *)
- &pSMBr->hdr.Protocol +data_offset),
- min_t(const int, buflen,count) / 2);
- /* BB FIXME investigate remapping reserved chars here */
- cifs_strfromUCS_le(symlinkinfo,
- (__le16 *) ((char *)&pSMBr->hdr.Protocol +
- data_offset),
- name_len, nls_codepage);
- } else {
- strncpy(symlinkinfo,
- (char *) &pSMBr->hdr.Protocol +
- data_offset,
- min_t(const int, buflen, count));
- }
- symlinkinfo[buflen] = 0;
- /* just in case so calling code does not go off the end of buffer */
- }
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto querySymLinkRetry;
- return rc;
- }
- /* Initialize NT TRANSACT SMB into small smb request buffer.
- This assumes that all NT TRANSACTS that we init here have
- total parm and data under about 400 bytes (to fit in small cifs
- buffer size), which is the case so far, it easily fits. NB:
- Setup words themselves and ByteCount
- MaxSetupCount (size of returned setup area) and
- MaxParameterCount (returned parms size) must be set by caller */
- static int
- smb_init_ntransact(const __u16 sub_command, const int setup_count,
- const int parm_len, struct cifsTconInfo *tcon,
- void ** ret_buf)
- {
- int rc;
- __u32 temp_offset;
- struct smb_com_ntransact_req * pSMB;
- rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
- (void **)&pSMB);
- if (rc)
- return rc;
- *ret_buf = (void *)pSMB;
- pSMB->Reserved = 0;
- pSMB->TotalParameterCount = cpu_to_le32(parm_len);
- pSMB->TotalDataCount = 0;
- pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
- MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->DataCount = pSMB->TotalDataCount;
- temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
- (setup_count * 2) - 4 /* for rfc1001 length itself */;
- pSMB->ParameterOffset = cpu_to_le32(temp_offset);
- pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
- pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
- pSMB->SubCommand = cpu_to_le16(sub_command);
- return 0;
- }
- static int
- validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
- int * pdatalen, int * pparmlen)
- {
- char * end_of_smb;
- __u32 data_count, data_offset, parm_count, parm_offset;
- struct smb_com_ntransact_rsp * pSMBr;
- if(buf == NULL)
- return -EINVAL;
- pSMBr = (struct smb_com_ntransact_rsp *)buf;
- /* ByteCount was converted from little endian in SendReceive */
- end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
- (char *)&pSMBr->ByteCount;
-
- data_offset = le32_to_cpu(pSMBr->DataOffset);
- data_count = le32_to_cpu(pSMBr->DataCount);
- parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
- parm_count = le32_to_cpu(pSMBr->ParameterCount);
- *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
- *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
- /* should we also check that parm and data areas do not overlap? */
- if(*ppparm > end_of_smb) {
- cFYI(1,("parms start after end of smb"));
- return -EINVAL;
- } else if(parm_count + *ppparm > end_of_smb) {
- cFYI(1,("parm end after end of smb"));
- return -EINVAL;
- } else if(*ppdata > end_of_smb) {
- cFYI(1,("data starts after end of smb"));
- return -EINVAL;
- } else if(data_count + *ppdata > end_of_smb) {
- cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
- *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
- return -EINVAL;
- } else if(parm_count + data_count > pSMBr->ByteCount) {
- cFYI(1,("parm count and data count larger than SMB"));
- return -EINVAL;
- }
- return 0;
- }
- int
- CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *searchName,
- char *symlinkinfo, const int buflen,__u16 fid,
- const struct nls_table *nls_codepage)
- {
- int rc = 0;
- int bytes_returned;
- int name_len;
- struct smb_com_transaction_ioctl_req * pSMB;
- struct smb_com_transaction_ioctl_rsp * pSMBr;
- cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
- rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- pSMB->TotalParameterCount = 0 ;
- pSMB->TotalDataCount = 0;
- pSMB->MaxParameterCount = cpu_to_le32(2);
- /* BB find exact data count max from sess structure BB */
- pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
- MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
- pSMB->MaxSetupCount = 4;
- pSMB->Reserved = 0;
- pSMB->ParameterOffset = 0;
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 4;
- pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
- pSMB->IsFsctl = 1; /* FSCTL */
- pSMB->IsRootFlag = 0;
- pSMB->Fid = fid; /* file handle always le */
- pSMB->ByteCount = 0;
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
- } else { /* decode response */
- __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
- __u32 data_count = le32_to_cpu(pSMBr->DataCount);
- if ((pSMBr->ByteCount < 2) || (data_offset > 512))
- /* BB also check enough total bytes returned */
- rc = -EIO; /* bad smb */
- else {
- if(data_count && (data_count < 2048)) {
- char * end_of_smb = 2 /* sizeof byte count */ +
- pSMBr->ByteCount +
- (char *)&pSMBr->ByteCount;
- struct reparse_data * reparse_buf = (struct reparse_data *)
- ((char *)&pSMBr->hdr.Protocol + data_offset);
- if((char*)reparse_buf >= end_of_smb) {
- rc = -EIO;
- goto qreparse_out;
- }
- if((reparse_buf->LinkNamesBuf +
- reparse_buf->TargetNameOffset +
- reparse_buf->TargetNameLen) >
- end_of_smb) {
- cFYI(1,("reparse buf extended beyond SMB"));
- rc = -EIO;
- goto qreparse_out;
- }
-
- if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len = UniStrnlen((wchar_t *)
- (reparse_buf->LinkNamesBuf +
- reparse_buf->TargetNameOffset),
- min(buflen/2, reparse_buf->TargetNameLen / 2));
- cifs_strfromUCS_le(symlinkinfo,
- (__le16 *) (reparse_buf->LinkNamesBuf +
- reparse_buf->TargetNameOffset),
- name_len, nls_codepage);
- } else { /* ASCII names */
- strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
- reparse_buf->TargetNameOffset,
- min_t(const int, buflen, reparse_buf->TargetNameLen));
- }
- } else {
- rc = -EIO;
- cFYI(1,("Invalid return data count on get reparse info ioctl"));
- }
- symlinkinfo[buflen] = 0; /* just in case so the caller
- does not go off the end of the buffer */
- cFYI(1,("readlink result - %s ",symlinkinfo));
- }
- }
- qreparse_out:
- cifs_buf_release(pSMB);
- /* Note: On -EAGAIN error only caller can retry on handle based calls
- since file handle passed in no longer valid */
- return rc;
- }
- #ifdef CONFIG_CIFS_POSIX
- /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
- static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
- {
- /* u8 cifs fields do not need le conversion */
- ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
- ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
- ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
- /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
- return;
- }
- /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
- static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
- const int acl_type,const int size_of_data_area)
- {
- int size = 0;
- int i;
- __u16 count;
- struct cifs_posix_ace * pACE;
- struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
- posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
- if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
- return -EOPNOTSUPP;
- if(acl_type & ACL_TYPE_ACCESS) {
- count = le16_to_cpu(cifs_acl->access_entry_count);
- pACE = &cifs_acl->ace_array[0];
- size = sizeof(struct cifs_posix_acl);
- size += sizeof(struct cifs_posix_ace) * count;
- /* check if we would go beyond end of SMB */
- if(size_of_data_area < size) {
- cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
- return -EINVAL;
- }
- } else if(acl_type & ACL_TYPE_DEFAULT) {
- count = le16_to_cpu(cifs_acl->access_entry_count);
- size = sizeof(struct cifs_posix_acl);
- size += sizeof(struct cifs_posix_ace) * count;
- /* skip past access ACEs to get to default ACEs */
- pACE = &cifs_acl->ace_array[count];
- count = le16_to_cpu(cifs_acl->default_entry_count);
- size += sizeof(struct cifs_posix_ace) * count;
- /* check if we would go beyond end of SMB */
- if(size_of_data_area < size)
- return -EINVAL;
- } else {
- /* illegal type */
- return -EINVAL;
- }
- size = posix_acl_xattr_size(count);
- if((buflen == 0) || (local_acl == NULL)) {
- /* used to query ACL EA size */
- } else if(size > buflen) {
- return -ERANGE;
- } else /* buffer big enough */ {
- local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
- for(i = 0;i < count ;i++) {
- cifs_convert_ace(&local_acl->a_entries[i],pACE);
- pACE ++;
- }
- }
- return size;
- }
- static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
- const posix_acl_xattr_entry * local_ace)
- {
- __u16 rc = 0; /* 0 = ACL converted ok */
- cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
- cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
- /* BB is there a better way to handle the large uid? */
- if(local_ace->e_id == cpu_to_le32(-1)) {
- /* Probably no need to le convert -1 on any arch but can not hurt */
- cifs_ace->cifs_uid = cpu_to_le64(-1);
- } else
- cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
- /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
- return rc;
- }
- /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
- static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
- const int acl_type)
- {
- __u16 rc = 0;
- struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
- posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
- int count;
- int i;
- if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
- return 0;
- count = posix_acl_xattr_count((size_t)buflen);
- cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
- count, buflen, le32_to_cpu(local_acl->a_version)));
- if(le32_to_cpu(local_acl->a_version) != 2) {
- cFYI(1,("unknown POSIX ACL version %d",
- le32_to_cpu(local_acl->a_version)));
- return 0;
- }
- cifs_acl->version = cpu_to_le16(1);
- if(acl_type == ACL_TYPE_ACCESS)
- cifs_acl->access_entry_count = cpu_to_le16(count);
- else if(acl_type == ACL_TYPE_DEFAULT)
- cifs_acl->default_entry_count = cpu_to_le16(count);
- else {
- cFYI(1,("unknown ACL type %d",acl_type));
- return 0;
- }
- for(i=0;i<count;i++) {
- rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
- &local_acl->a_entries[i]);
- if(rc != 0) {
- /* ACE not converted */
- break;
- }
- }
- if(rc == 0) {
- rc = (__u16)(count * sizeof(struct cifs_posix_ace));
- rc += sizeof(struct cifs_posix_acl);
- /* BB add check to make sure ACL does not overflow SMB */
- }
- return rc;
- }
- int
- CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *searchName,
- char *acl_inf, const int buflen, const int acl_type,
- const struct nls_table *nls_codepage, int remap)
- {
- /* SMB_QUERY_POSIX_ACL */
- TRANSACTION2_QPI_REQ *pSMB = NULL;
- TRANSACTION2_QPI_RSP *pSMBr = NULL;
- int rc = 0;
- int bytes_returned;
- int name_len;
- __u16 params, byte_count;
-
- cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
- queryAclRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
-
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- pSMB->FileName[name_len] = 0;
- pSMB->FileName[name_len+1] = 0;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(searchName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, searchName, name_len);
- }
- params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
- pSMB->TotalDataCount = 0;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- /* BB find exact max data count below from sess structure BB */
- pSMB->MaxDataCount = cpu_to_le16(4000);
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- pSMB->ParameterOffset = cpu_to_le16(
- offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
- byte_count = params + 1 /* pad */ ;
- pSMB->TotalParameterCount = cpu_to_le16(params);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_acl_get);
- if (rc) {
- cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
- } else {
- /* decode response */
-
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 2))
- /* BB also check enough total bytes returned */
- rc = -EIO; /* bad smb */
- else {
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
- rc = cifs_copy_posix_acl(acl_inf,
- (char *)&pSMBr->hdr.Protocol+data_offset,
- buflen,acl_type,count);
- }
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto queryAclRetry;
- return rc;
- }
- int
- CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *fileName,
- const char *local_acl, const int buflen,
- const int acl_type,
- const struct nls_table *nls_codepage, int remap)
- {
- struct smb_com_transaction2_spi_req *pSMB = NULL;
- struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
- char *parm_data;
- int name_len;
- int rc = 0;
- int bytes_returned = 0;
- __u16 params, byte_count, data_count, param_offset, offset;
- cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
- setAclRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(fileName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, fileName, name_len);
- }
- params = 6 + name_len;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
- offset = param_offset + params;
- parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
- pSMB->ParameterOffset = cpu_to_le16(param_offset);
- /* convert to on the wire format for POSIX ACL */
- data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
- if(data_count == 0) {
- rc = -EOPNOTSUPP;
- goto setACLerrorExit;
- }
- pSMB->DataOffset = cpu_to_le16(offset);
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
- pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
- byte_count = 3 /* pad */ + params + data_count;
- pSMB->DataCount = cpu_to_le16(data_count);
- pSMB->TotalDataCount = pSMB->DataCount;
- pSMB->ParameterCount = cpu_to_le16(params);
- pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Set POSIX ACL returned %d", rc));
- }
- setACLerrorExit:
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto setAclRetry;
- return rc;
- }
- /* BB fix tabs in this function FIXME BB */
- int
- CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
- const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
- {
- int rc = 0;
- struct smb_t2_qfi_req *pSMB = NULL;
- struct smb_t2_qfi_rsp *pSMBr = NULL;
- int bytes_returned;
- __u16 params, byte_count;
- cFYI(1,("In GetExtAttr"));
- if(tcon == NULL)
- return -ENODEV;
- GetExtAttrRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- params = 2 /* level */ +2 /* fid */;
- pSMB->t2.TotalDataCount = 0;
- pSMB->t2.MaxParameterCount = cpu_to_le16(4);
- /* BB find exact max data count below from sess structure BB */
- pSMB->t2.MaxDataCount = cpu_to_le16(4000);
- pSMB->t2.MaxSetupCount = 0;
- pSMB->t2.Reserved = 0;
- pSMB->t2.Flags = 0;
- pSMB->t2.Timeout = 0;
- pSMB->t2.Reserved2 = 0;
- pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
- Fid) - 4);
- pSMB->t2.DataCount = 0;
- pSMB->t2.DataOffset = 0;
- pSMB->t2.SetupCount = 1;
- pSMB->t2.Reserved3 = 0;
- pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
- byte_count = params + 1 /* pad */ ;
- pSMB->t2.TotalParameterCount = cpu_to_le16(params);
- pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
- pSMB->Pad = 0;
- pSMB->Fid = netfid;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->t2.ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("error %d in GetExtAttr", rc));
- } else {
- /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 2))
- /* BB also check enough total bytes returned */
- /* If rc should we check for EOPNOSUPP and
- disable the srvino flag? or in caller? */
- rc = -EIO; /* bad smb */
- else {
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
- struct file_chattr_info * pfinfo;
- /* BB Do we need a cast or hash here ? */
- if(count != 16) {
- cFYI(1, ("Illegal size ret in GetExtAttr"));
- rc = -EIO;
- goto GetExtAttrOut;
- }
- pfinfo = (struct file_chattr_info *)
- (data_offset + (char *) &pSMBr->hdr.Protocol);
- *pExtAttrBits = le64_to_cpu(pfinfo->mode);
- *pMask = le64_to_cpu(pfinfo->mask);
- }
- }
- GetExtAttrOut:
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto GetExtAttrRetry;
- return rc;
- }
- #endif /* CONFIG_POSIX */
- /* security id for everyone */
- const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
- /* group users */
- const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
- /* Convert CIFS ACL to POSIX form */
- static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
- {
- return 0;
- }
- /* Get Security Descriptor (by handle) from remote server for a file or dir */
- int
- CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
- /* BB fix up return info */ char *acl_inf, const int buflen,
- const int acl_type /* ACCESS/DEFAULT not sure implication */)
- {
- int rc = 0;
- int buf_type = 0;
- QUERY_SEC_DESC_REQ * pSMB;
- struct kvec iov[1];
- cFYI(1, ("GetCifsACL"));
- rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
- 8 /* parm len */, tcon, (void **) &pSMB);
- if (rc)
- return rc;
- pSMB->MaxParameterCount = cpu_to_le32(4);
- /* BB TEST with big acls that might need to be e.g. larger than 16K */
- pSMB->MaxSetupCount = 0;
- pSMB->Fid = fid; /* file handle always le */
- pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
- CIFS_ACL_DACL);
- pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
- pSMB->hdr.smb_buf_length += 11;
- iov[0].iov_base = (char *)pSMB;
- iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
- rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
- cifs_stats_inc(&tcon->num_acl_get);
- if (rc) {
- cFYI(1, ("Send error in QuerySecDesc = %d", rc));
- } else { /* decode response */
- struct cifs_sid * psec_desc;
- __le32 * parm;
- int parm_len;
- int data_len;
- int acl_len;
- struct smb_com_ntransact_rsp * pSMBr;
- /* validate_nttransact */
- rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
- (char **)&psec_desc,
- &parm_len, &data_len);
-
- if(rc)
- goto qsec_out;
- pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
- cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
- if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
- rc = -EIO; /* bad smb */
- goto qsec_out;
- }
- /* BB check that data area is minimum length and as big as acl_len */
- acl_len = le32_to_cpu(*(__le32 *)parm);
- /* BB check if(acl_len > bufsize) */
- parse_sec_desc(psec_desc, acl_len);
- }
- qsec_out:
- if(buf_type == CIFS_SMALL_BUFFER)
- cifs_small_buf_release(iov[0].iov_base);
- else if(buf_type == CIFS_LARGE_BUFFER)
- cifs_buf_release(iov[0].iov_base);
- cifs_small_buf_release(pSMB);
- return rc;
- }
- /* Legacy Query Path Information call for lookup to old servers such
- as Win9x/WinME */
- int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *searchName,
- FILE_ALL_INFO * pFinfo,
- const struct nls_table *nls_codepage, int remap)
- {
- QUERY_INFORMATION_REQ * pSMB;
- QUERY_INFORMATION_RSP * pSMBr;
- int rc = 0;
- int bytes_returned;
- int name_len;
- cFYI(1, ("In SMBQPath path %s", searchName));
- QInfRetry:
- rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else {
- name_len = strnlen(searchName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, searchName, name_len);
- }
- pSMB->BufferFormat = 0x04;
- name_len++; /* account for buffer type byte */
- pSMB->hdr.smb_buf_length += (__u16) name_len;
- pSMB->ByteCount = cpu_to_le16(name_len);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Send error in QueryInfo = %d", rc));
- } else if (pFinfo) { /* decode response */
- memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
- pFinfo->AllocationSize =
- cpu_to_le64(le32_to_cpu(pSMBr->size));
- pFinfo->EndOfFile = pFinfo->AllocationSize;
- pFinfo->Attributes =
- cpu_to_le32(le16_to_cpu(pSMBr->attr));
- } else
- rc = -EIO; /* bad buffer passed in */
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto QInfRetry;
- return rc;
- }
- int
- CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *searchName,
- FILE_ALL_INFO * pFindData,
- const struct nls_table *nls_codepage, int remap)
- {
- /* level 263 SMB_QUERY_FILE_ALL_INFO */
- TRANSACTION2_QPI_REQ *pSMB = NULL;
- TRANSACTION2_QPI_RSP *pSMBr = NULL;
- int rc = 0;
- int bytes_returned;
- int name_len;
- __u16 params, byte_count;
- /* cFYI(1, ("In QPathInfo path %s", searchName)); */
- QPathInfoRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(searchName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, searchName, name_len);
- }
- params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
- pSMB->TotalDataCount = 0;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
- byte_count = params + 1 /* pad */ ;
- pSMB->TotalParameterCount = cpu_to_le16(params);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Send error in QPathInfo = %d", rc));
- } else { /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 40))
- rc = -EIO; /* bad smb */
- else if (pFindData){
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- memcpy((char *) pFindData,
- (char *) &pSMBr->hdr.Protocol +
- data_offset, sizeof (FILE_ALL_INFO));
- } else
- rc = -ENOMEM;
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto QPathInfoRetry;
- return rc;
- }
- int
- CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *searchName,
- FILE_UNIX_BASIC_INFO * pFindData,
- const struct nls_table *nls_codepage, int remap)
- {
- /* SMB_QUERY_FILE_UNIX_BASIC */
- TRANSACTION2_QPI_REQ *pSMB = NULL;
- TRANSACTION2_QPI_RSP *pSMBr = NULL;
- int rc = 0;
- int bytes_returned = 0;
- int name_len;
- __u16 params, byte_count;
- cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
- UnixQPathInfoRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(searchName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, searchName, name_len);
- }
- params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
- pSMB->TotalDataCount = 0;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- /* BB find exact max SMB PDU from sess structure BB */
- pSMB->MaxDataCount = cpu_to_le16(4000);
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
- byte_count = params + 1 /* pad */ ;
- pSMB->TotalParameterCount = cpu_to_le16(params);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Send error in QPathInfo = %d", rc));
- } else { /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
- rc = -EIO; /* bad smb */
- } else {
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- memcpy((char *) pFindData,
- (char *) &pSMBr->hdr.Protocol +
- data_offset,
- sizeof (FILE_UNIX_BASIC_INFO));
- }
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto UnixQPathInfoRetry;
- return rc;
- }
- #if 0 /* function unused at present */
- int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
- const char *searchName, FILE_ALL_INFO * findData,
- const struct nls_table *nls_codepage)
- {
- /* level 257 SMB_ */
- TRANSACTION2_FFIRST_REQ *pSMB = NULL;
- TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
- int rc = 0;
- int bytes_returned;
- int name_len;
- __u16 params, byte_count;
- cFYI(1, ("In FindUnique"));
- findUniqueRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(searchName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, searchName, name_len);
- }
- params = 12 + name_len /* includes null */ ;
- pSMB->TotalDataCount = 0; /* no EAs */
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- pSMB->ParameterOffset = cpu_to_le16(
- offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 1; /* one byte, no need to le convert */
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
- byte_count = params + 1 /* pad */ ;
- pSMB->TotalParameterCount = cpu_to_le16(params);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->SearchAttributes =
- cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
- ATTR_DIRECTORY);
- pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
- pSMB->SearchFlags = cpu_to_le16(1);
- pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
- pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
- } else { /* decode response */
- cifs_stats_inc(&tcon->num_ffirst);
- /* BB fill in */
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto findUniqueRetry;
- return rc;
- }
- #endif /* end unused (temporarily) function */
- /* xid, tcon, searchName and codepage are input parms, rest are returned */
- int
- CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
- const char *searchName,
- const struct nls_table *nls_codepage,
- __u16 * pnetfid,
- struct cifs_search_info * psrch_inf, int remap, const char dirsep)
- {
- /* level 257 SMB_ */
- TRANSACTION2_FFIRST_REQ *pSMB = NULL;
- TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
- T2_FFIRST_RSP_PARMS * parms;
- int rc = 0;
- int bytes_returned = 0;
- int name_len;
- __u16 params, byte_count;
- cFYI(1, ("In FindFirst for %s",searchName));
- findFirstRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
- PATH_MAX, nls_codepage, remap);
- /* We can not add the asterik earlier in case
- it got remapped to 0xF03A as if it were part of the
- directory name instead of a wildcard */
- name_len *= 2;
- pSMB->FileName[name_len] = dirsep;
- pSMB->FileName[name_len+1] = 0;
- pSMB->FileName[name_len+2] = '*';
- pSMB->FileName[name_len+3] = 0;
- name_len += 4; /* now the trailing null */
- pSMB->FileName[name_len] = 0; /* null terminate just in case */
- pSMB->FileName[name_len+1] = 0;
- name_len += 2;
- } else { /* BB add check for overrun of SMB buf BB */
- name_len = strnlen(searchName, PATH_MAX);
- /* BB fix here and in unicode clause above ie
- if(name_len > buffersize-header)
- free buffer exit; BB */
- strncpy(pSMB->FileName, searchName, name_len);
- pSMB->FileName[name_len] = dirsep;
- pSMB->FileName[name_len+1] = '*';
- pSMB->FileName[name_len+2] = 0;
- name_len += 3;
- }
- params = 12 + name_len /* includes null */ ;
- pSMB->TotalDataCount = 0; /* no EAs */
- pSMB->MaxParameterCount = cpu_to_le16(10);
- pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
- MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- byte_count = params + 1 /* pad */ ;
- pSMB->TotalParameterCount = cpu_to_le16(params);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->ParameterOffset = cpu_to_le16(
- offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
- pSMB->SearchAttributes =
- cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
- ATTR_DIRECTORY);
- pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
- pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
- CIFS_SEARCH_RETURN_RESUME);
- pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
- /* BB what should we set StorageType to? Does it matter? BB */
- pSMB->SearchStorageType = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_ffirst);
- if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
- /* BB Add code to handle unsupported level rc */
- cFYI(1, ("Error in FindFirst = %d", rc));
- if (pSMB)
- cifs_buf_release(pSMB);
- /* BB eventually could optimize out free and realloc of buf */
- /* for this case */
- if (rc == -EAGAIN)
- goto findFirstRetry;
- } else { /* decode response */
- /* BB remember to free buffer if error BB */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if(rc == 0) {
- if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
- psrch_inf->unicode = TRUE;
- else
- psrch_inf->unicode = FALSE;
- psrch_inf->ntwrk_buf_start = (char *)pSMBr;
- psrch_inf->srch_entries_start =
- (char *) &pSMBr->hdr.Protocol +
- le16_to_cpu(pSMBr->t2.DataOffset);
- parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
- le16_to_cpu(pSMBr->t2.ParameterOffset));
- if(parms->EndofSearch)
- psrch_inf->endOfSearch = TRUE;
- else
- psrch_inf->endOfSearch = FALSE;
- psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
- psrch_inf->index_of_last_entry =
- psrch_inf->entries_in_buffer;
- *pnetfid = parms->SearchHandle;
- } else {
- cifs_buf_release(pSMB);
- }
- }
- return rc;
- }
- int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
- __u16 searchHandle, struct cifs_search_info * psrch_inf)
- {
- TRANSACTION2_FNEXT_REQ *pSMB = NULL;
- TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
- T2_FNEXT_RSP_PARMS * parms;
- char *response_data;
- int rc = 0;
- int bytes_returned, name_len;
- __u16 params, byte_count;
- cFYI(1, ("In FindNext"));
- if(psrch_inf->endOfSearch == TRUE)
- return -ENOENT;
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- params = 14; /* includes 2 bytes of null string, converted to LE below */
- byte_count = 0;
- pSMB->TotalDataCount = 0; /* no EAs */
- pSMB->MaxParameterCount = cpu_to_le16(8);
- pSMB->MaxDataCount =
- cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- pSMB->ParameterOffset = cpu_to_le16(
- offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
- pSMB->SearchHandle = searchHandle; /* always kept as le */
- pSMB->SearchCount =
- cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
- /* test for Unix extensions */
- /* if (tcon->ses->capabilities & CAP_UNIX) {
- pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
- psrch_inf->info_level = SMB_FIND_FILE_UNIX;
- } else {
- pSMB->InformationLevel =
- cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
- psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
- } */
- pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
- pSMB->ResumeKey = psrch_inf->resume_key;
- pSMB->SearchFlags =
- cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
- name_len = psrch_inf->resume_name_len;
- params += name_len;
- if(name_len < PATH_MAX) {
- memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
- byte_count += name_len;
- /* 14 byte parm len above enough for 2 byte null terminator */
- pSMB->ResumeFileName[name_len] = 0;
- pSMB->ResumeFileName[name_len+1] = 0;
- } else {
- rc = -EINVAL;
- goto FNext2_err_exit;
- }
- byte_count = params + 1 /* pad */ ;
- pSMB->TotalParameterCount = cpu_to_le16(params);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
-
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- cifs_stats_inc(&tcon->num_fnext);
- if (rc) {
- if (rc == -EBADF) {
- psrch_inf->endOfSearch = TRUE;
- rc = 0; /* search probably was closed at end of search above */
- } else
- cFYI(1, ("FindNext returned = %d", rc));
- } else { /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
-
- if(rc == 0) {
- /* BB fixme add lock for file (srch_info) struct here */
- if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
- psrch_inf->unicode = TRUE;
- else
- psrch_inf->unicode = FALSE;
- response_data = (char *) &pSMBr->hdr.Protocol +
- le16_to_cpu(pSMBr->t2.ParameterOffset);
- parms = (T2_FNEXT_RSP_PARMS *)response_data;
- response_data = (char *)&pSMBr->hdr.Protocol +
- le16_to_cpu(pSMBr->t2.DataOffset);
- cifs_buf_release(psrch_inf->ntwrk_buf_start);
- psrch_inf->srch_entries_start = response_data;
- psrch_inf->ntwrk_buf_start = (char *)pSMB;
- if(parms->EndofSearch)
- psrch_inf->endOfSearch = TRUE;
- else
- psrch_inf->endOfSearch = FALSE;
-
- psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
- psrch_inf->index_of_last_entry +=
- psrch_inf->entries_in_buffer;
- /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
- /* BB fixme add unlock here */
- }
- }
- /* BB On error, should we leave previous search buf (and count and
- last entry fields) intact or free the previous one? */
- /* Note: On -EAGAIN error only caller can retry on handle based calls
- since file handle passed in no longer valid */
- FNext2_err_exit:
- if (rc != 0)
- cifs_buf_release(pSMB);
-
- return rc;
- }
- int
- CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
- {
- int rc = 0;
- FINDCLOSE_REQ *pSMB = NULL;
- CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
- int bytes_returned;
- cFYI(1, ("In CIFSSMBFindClose"));
- rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
- /* no sense returning error if session restarted
- as file handle has been closed */
- if(rc == -EAGAIN)
- return 0;
- if (rc)
- return rc;
- pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
- pSMB->FileID = searchHandle;
- pSMB->ByteCount = 0;
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cERROR(1, ("Send error in FindClose = %d", rc));
- }
- cifs_stats_inc(&tcon->num_fclose);
- cifs_small_buf_release(pSMB);
- /* Since session is dead, search handle closed on server already */
- if (rc == -EAGAIN)
- rc = 0;
- return rc;
- }
- int
- CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *searchName,
- __u64 * inode_number,
- const struct nls_table *nls_codepage, int remap)
- {
- int rc = 0;
- TRANSACTION2_QPI_REQ *pSMB = NULL;
- TRANSACTION2_QPI_RSP *pSMBr = NULL;
- int name_len, bytes_returned;
- __u16 params, byte_count;
- cFYI(1,("In GetSrvInodeNum for %s",searchName));
- if(tcon == NULL)
- return -ENODEV;
- GetInodeNumberRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
- PATH_MAX,nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(searchName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, searchName, name_len);
- }
- params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
- pSMB->TotalDataCount = 0;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- /* BB find exact max data count below from sess structure BB */
- pSMB->MaxDataCount = cpu_to_le16(4000);
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
- byte_count = params + 1 /* pad */ ;
- pSMB->TotalParameterCount = cpu_to_le16(params);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("error %d in QueryInternalInfo", rc));
- } else {
- /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 2))
- /* BB also check enough total bytes returned */
- /* If rc should we check for EOPNOSUPP and
- disable the srvino flag? or in caller? */
- rc = -EIO; /* bad smb */
- else {
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
- struct file_internal_info * pfinfo;
- /* BB Do we need a cast or hash here ? */
- if(count < 8) {
- cFYI(1, ("Illegal size ret in QryIntrnlInf"));
- rc = -EIO;
- goto GetInodeNumOut;
- }
- pfinfo = (struct file_internal_info *)
- (data_offset + (char *) &pSMBr->hdr.Protocol);
- *inode_number = pfinfo->UniqueId;
- }
- }
- GetInodeNumOut:
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto GetInodeNumberRetry;
- return rc;
- }
- int
- CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
- const unsigned char *searchName,
- unsigned char **targetUNCs,
- unsigned int *number_of_UNC_in_array,
- const struct nls_table *nls_codepage, int remap)
- {
- /* TRANS2_GET_DFS_REFERRAL */
- TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
- TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
- struct dfs_referral_level_3 * referrals = NULL;
- int rc = 0;
- int bytes_returned;
- int name_len;
- unsigned int i;
- char * temp;
- __u16 params, byte_count;
- *number_of_UNC_in_array = 0;
- *targetUNCs = NULL;
- cFYI(1, ("In GetDFSRefer the path %s", searchName));
- if (ses == NULL)
- return -ENODEV;
- getDFSRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
-
- /* server pointer checked in called function,
- but should never be null here anyway */
- pSMB->hdr.Mid = GetNextMid(ses->server);
- pSMB->hdr.Tid = ses->ipc_tid;
- pSMB->hdr.Uid = ses->Suid;
- if (ses->capabilities & CAP_STATUS32) {
- pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
- }
- if (ses->capabilities & CAP_DFS) {
- pSMB->hdr.Flags2 |= SMBFLG2_DFS;
- }
- if (ses->capabilities & CAP_UNICODE) {
- pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
- searchName, PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(searchName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->RequestFileName, searchName, name_len);
- }
- params = 2 /* level */ + name_len /*includes null */ ;
- pSMB->TotalDataCount = 0;
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->MaxParameterCount = 0;
- pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
- byte_count = params + 3 /* pad */ ;
- pSMB->ParameterCount = cpu_to_le16(params);
- pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->MaxReferralLevel = cpu_to_le16(3);
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Send error in GetDFSRefer = %d", rc));
- } else { /* decode response */
- /* BB Add logic to parse referrals here */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
- rc = -EIO; /* bad smb */
- else {
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
- cFYI(1,
- ("Decoding GetDFSRefer response. BCC: %d Offset %d",
- pSMBr->ByteCount, data_offset));
- referrals =
- (struct dfs_referral_level_3 *)
- (8 /* sizeof start of data block */ +
- data_offset +
- (char *) &pSMBr->hdr.Protocol);
- cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",
- le16_to_cpu(pSMBr->NumberOfReferrals),le16_to_cpu(pSMBr->DFSFlags), le16_to_cpu(referrals->ReferralSize),le16_to_cpu(referrals->ServerType),le16_to_cpu(referrals->ReferralFlags),le16_to_cpu(referrals->TimeToLive)));
- /* BB This field is actually two bytes in from start of
- data block so we could do safety check that DataBlock
- begins at address of pSMBr->NumberOfReferrals */
- *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
- /* BB Fix below so can return more than one referral */
- if(*number_of_UNC_in_array > 1)
- *number_of_UNC_in_array = 1;
- /* get the length of the strings describing refs */
- name_len = 0;
- for(i=0;i<*number_of_UNC_in_array;i++) {
- /* make sure that DfsPathOffset not past end */
- __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
- if (offset > data_count) {
- /* if invalid referral, stop here and do
- not try to copy any more */
- *number_of_UNC_in_array = i;
- break;
- }
- temp = ((char *)referrals) + offset;
- if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len += UniStrnlen((wchar_t *)temp,data_count);
- } else {
- name_len += strnlen(temp,data_count);
- }
- referrals++;
- /* BB add check that referral pointer does not fall off end PDU */
-
- }
- /* BB add check for name_len bigger than bcc */
- *targetUNCs =
- kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
- if(*targetUNCs == NULL) {
- rc = -ENOMEM;
- goto GetDFSRefExit;
- }
- /* copy the ref strings */
- referrals =
- (struct dfs_referral_level_3 *)
- (8 /* sizeof data hdr */ +
- data_offset +
- (char *) &pSMBr->hdr.Protocol);
- for(i=0;i<*number_of_UNC_in_array;i++) {
- temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
- if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
- cifs_strfromUCS_le(*targetUNCs,
- (__le16 *) temp, name_len, nls_codepage);
- } else {
- strncpy(*targetUNCs,temp,name_len);
- }
- /* BB update target_uncs pointers */
- referrals++;
- }
- temp = *targetUNCs;
- temp[name_len] = 0;
- }
- }
- GetDFSRefExit:
- if (pSMB)
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto getDFSRetry;
- return rc;
- }
- /* Query File System Info such as free space to old servers such as Win 9x */
- int
- SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
- {
- /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
- TRANSACTION2_QFSI_REQ *pSMB = NULL;
- TRANSACTION2_QFSI_RSP *pSMBr = NULL;
- FILE_SYSTEM_ALLOC_INFO *response_data;
- int rc = 0;
- int bytes_returned = 0;
- __u16 params, byte_count;
- cFYI(1, ("OldQFSInfo"));
- oldQFSInfoRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- params = 2; /* level */
- pSMB->TotalDataCount = 0;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(1000);
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- byte_count = params + 1 /* pad */ ;
- pSMB->TotalParameterCount = cpu_to_le16(params);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
- pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Send error in QFSInfo = %d", rc));
- } else { /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 18))
- rc = -EIO; /* bad smb */
- else {
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- cFYI(1,("qfsinf resp BCC: %d Offset %d",
- pSMBr->ByteCount, data_offset));
- response_data =
- (FILE_SYSTEM_ALLOC_INFO *)
- (((char *) &pSMBr->hdr.Protocol) + data_offset);
- FSData->f_bsize =
- le16_to_cpu(response_data->BytesPerSector) *
- le32_to_cpu(response_data->
- SectorsPerAllocationUnit);
- FSData->f_blocks =
- le32_to_cpu(response_data->TotalAllocationUnits);
- FSData->f_bfree = FSData->f_bavail =
- le32_to_cpu(response_data->FreeAllocationUnits);
- cFYI(1,
- ("Blocks: %lld Free: %lld Block size %ld",
- (unsigned long long)FSData->f_blocks,
- (unsigned long long)FSData->f_bfree,
- FSData->f_bsize));
- }
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto oldQFSInfoRetry;
- return rc;
- }
- int
- CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
- {
- /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
- TRANSACTION2_QFSI_REQ *pSMB = NULL;
- TRANSACTION2_QFSI_RSP *pSMBr = NULL;
- FILE_SYSTEM_INFO *response_data;
- int rc = 0;
- int bytes_returned = 0;
- __u16 params, byte_count;
- cFYI(1, ("In QFSInfo"));
- QFSInfoRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- params = 2; /* level */
- pSMB->TotalDataCount = 0;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(1000);
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- byte_count = params + 1 /* pad */ ;
- pSMB->TotalParameterCount = cpu_to_le16(params);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Send error in QFSInfo = %d", rc));
- } else { /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 24))
- rc = -EIO; /* bad smb */
- else {
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- response_data =
- (FILE_SYSTEM_INFO
- *) (((char *) &pSMBr->hdr.Protocol) +
- data_offset);
- FSData->f_bsize =
- le32_to_cpu(response_data->BytesPerSector) *
- le32_to_cpu(response_data->
- SectorsPerAllocationUnit);
- FSData->f_blocks =
- le64_to_cpu(response_data->TotalAllocationUnits);
- FSData->f_bfree = FSData->f_bavail =
- le64_to_cpu(response_data->FreeAllocationUnits);
- cFYI(1,
- ("Blocks: %lld Free: %lld Block size %ld",
- (unsigned long long)FSData->f_blocks,
- (unsigned long long)FSData->f_bfree,
- FSData->f_bsize));
- }
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto QFSInfoRetry;
- return rc;
- }
- int
- CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
- {
- /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
- TRANSACTION2_QFSI_REQ *pSMB = NULL;
- TRANSACTION2_QFSI_RSP *pSMBr = NULL;
- FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
- int rc = 0;
- int bytes_returned = 0;
- __u16 params, byte_count;
- cFYI(1, ("In QFSAttributeInfo"));
- QFSAttributeRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- params = 2; /* level */
- pSMB->TotalDataCount = 0;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- byte_count = params + 1 /* pad */ ;
- pSMB->TotalParameterCount = cpu_to_le16(params);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
- } else { /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
- rc = -EIO; /* bad smb */
- } else {
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- response_data =
- (FILE_SYSTEM_ATTRIBUTE_INFO
- *) (((char *) &pSMBr->hdr.Protocol) +
- data_offset);
- memcpy(&tcon->fsAttrInfo, response_data,
- sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
- }
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto QFSAttributeRetry;
- return rc;
- }
- int
- CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
- {
- /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
- TRANSACTION2_QFSI_REQ *pSMB = NULL;
- TRANSACTION2_QFSI_RSP *pSMBr = NULL;
- FILE_SYSTEM_DEVICE_INFO *response_data;
- int rc = 0;
- int bytes_returned = 0;
- __u16 params, byte_count;
- cFYI(1, ("In QFSDeviceInfo"));
- QFSDeviceRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- params = 2; /* level */
- pSMB->TotalDataCount = 0;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- byte_count = params + 1 /* pad */ ;
- pSMB->TotalParameterCount = cpu_to_le16(params);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
- } else { /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
- rc = -EIO; /* bad smb */
- else {
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- response_data =
- (FILE_SYSTEM_DEVICE_INFO *)
- (((char *) &pSMBr->hdr.Protocol) +
- data_offset);
- memcpy(&tcon->fsDevInfo, response_data,
- sizeof (FILE_SYSTEM_DEVICE_INFO));
- }
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto QFSDeviceRetry;
- return rc;
- }
- int
- CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
- {
- /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
- TRANSACTION2_QFSI_REQ *pSMB = NULL;
- TRANSACTION2_QFSI_RSP *pSMBr = NULL;
- FILE_SYSTEM_UNIX_INFO *response_data;
- int rc = 0;
- int bytes_returned = 0;
- __u16 params, byte_count;
- cFYI(1, ("In QFSUnixInfo"));
- QFSUnixRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- params = 2; /* level */
- pSMB->TotalDataCount = 0;
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- byte_count = params + 1 /* pad */ ;
- pSMB->ParameterCount = cpu_to_le16(params);
- pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
- smb_com_transaction2_qfsi_req, InformationLevel) - 4);
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
- } else { /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 13)) {
- rc = -EIO; /* bad smb */
- } else {
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- response_data =
- (FILE_SYSTEM_UNIX_INFO
- *) (((char *) &pSMBr->hdr.Protocol) +
- data_offset);
- memcpy(&tcon->fsUnixInfo, response_data,
- sizeof (FILE_SYSTEM_UNIX_INFO));
- }
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto QFSUnixRetry;
- return rc;
- }
- int
- CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
- {
- /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
- TRANSACTION2_SETFSI_REQ *pSMB = NULL;
- TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
- int rc = 0;
- int bytes_returned = 0;
- __u16 params, param_offset, offset, byte_count;
- cFYI(1, ("In SETFSUnixInfo"));
- SETFSUnixRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- params = 4; /* 2 bytes zero followed by info level. */
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
- offset = param_offset + params;
- pSMB->MaxParameterCount = cpu_to_le16(4);
- pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
- byte_count = 1 /* pad */ + params + 12;
- pSMB->DataCount = cpu_to_le16(12);
- pSMB->ParameterCount = cpu_to_le16(params);
- pSMB->TotalDataCount = pSMB->DataCount;
- pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->ParameterOffset = cpu_to_le16(param_offset);
- pSMB->DataOffset = cpu_to_le16(offset);
- /* Params. */
- pSMB->FileNum = 0;
- pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
- /* Data. */
- pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
- pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
- pSMB->ClientUnixCap = cpu_to_le64(cap);
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
- } else { /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc) {
- rc = -EIO; /* bad smb */
- }
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto SETFSUnixRetry;
- return rc;
- }
- int
- CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
- struct kstatfs *FSData)
- {
- /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
- TRANSACTION2_QFSI_REQ *pSMB = NULL;
- TRANSACTION2_QFSI_RSP *pSMBr = NULL;
- FILE_SYSTEM_POSIX_INFO *response_data;
- int rc = 0;
- int bytes_returned = 0;
- __u16 params, byte_count;
- cFYI(1, ("In QFSPosixInfo"));
- QFSPosixRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- params = 2; /* level */
- pSMB->TotalDataCount = 0;
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- byte_count = params + 1 /* pad */ ;
- pSMB->ParameterCount = cpu_to_le16(params);
- pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
- smb_com_transaction2_qfsi_req, InformationLevel) - 4);
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
- } else { /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 13)) {
- rc = -EIO; /* bad smb */
- } else {
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- response_data =
- (FILE_SYSTEM_POSIX_INFO
- *) (((char *) &pSMBr->hdr.Protocol) +
- data_offset);
- FSData->f_bsize =
- le32_to_cpu(response_data->BlockSize);
- FSData->f_blocks =
- le64_to_cpu(response_data->TotalBlocks);
- FSData->f_bfree =
- le64_to_cpu(response_data->BlocksAvail);
- if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
- FSData->f_bavail = FSData->f_bfree;
- } else {
- FSData->f_bavail =
- le64_to_cpu(response_data->UserBlocksAvail);
- }
- if(response_data->TotalFileNodes != cpu_to_le64(-1))
- FSData->f_files =
- le64_to_cpu(response_data->TotalFileNodes);
- if(response_data->FreeFileNodes != cpu_to_le64(-1))
- FSData->f_ffree =
- le64_to_cpu(response_data->FreeFileNodes);
- }
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto QFSPosixRetry;
- return rc;
- }
- /* We can not use write of zero bytes trick to
- set file size due to need for large file support. Also note that
- this SetPathInfo is preferred to SetFileInfo based method in next
- routine which is only needed to work around a sharing violation bug
- in Samba which this routine can run into */
- int
- CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
- __u64 size, int SetAllocation,
- const struct nls_table *nls_codepage, int remap)
- {
- struct smb_com_transaction2_spi_req *pSMB = NULL;
- struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
- struct file_end_of_file_info *parm_data;
- int name_len;
- int rc = 0;
- int bytes_returned = 0;
- __u16 params, byte_count, data_count, param_offset, offset;
- cFYI(1, ("In SetEOF"));
- SetEOFRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(fileName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, fileName, name_len);
- }
- params = 6 + name_len;
- data_count = sizeof (struct file_end_of_file_info);
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(4100);
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
- offset = param_offset + params;
- if(SetAllocation) {
- if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
- pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
- else
- pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
- } else /* Set File Size */ {
- if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
- pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
- else
- pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
- }
- parm_data =
- (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
- offset);
- pSMB->ParameterOffset = cpu_to_le16(param_offset);
- pSMB->DataOffset = cpu_to_le16(offset);
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
- byte_count = 3 /* pad */ + params + data_count;
- pSMB->DataCount = cpu_to_le16(data_count);
- pSMB->TotalDataCount = pSMB->DataCount;
- pSMB->ParameterCount = cpu_to_le16(params);
- pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- parm_data->FileSize = cpu_to_le64(size);
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("SetPathInfo (file size) returned %d", rc));
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto SetEOFRetry;
- return rc;
- }
- int
- CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
- __u16 fid, __u32 pid_of_opener, int SetAllocation)
- {
- struct smb_com_transaction2_sfi_req *pSMB = NULL;
- struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
- char *data_offset;
- struct file_end_of_file_info *parm_data;
- int rc = 0;
- int bytes_returned = 0;
- __u16 params, param_offset, offset, byte_count, count;
- cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
- (long long)size));
- rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
- if (rc)
- return rc;
- pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
- pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
- pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
-
- params = 6;
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
- offset = param_offset + params;
- data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
- count = sizeof(struct file_end_of_file_info);
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
- byte_count = 3 /* pad */ + params + count;
- pSMB->DataCount = cpu_to_le16(count);
- pSMB->ParameterCount = cpu_to_le16(params);
- pSMB->TotalDataCount = pSMB->DataCount;
- pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->ParameterOffset = cpu_to_le16(param_offset);
- parm_data =
- (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
- offset);
- pSMB->DataOffset = cpu_to_le16(offset);
- parm_data->FileSize = cpu_to_le64(size);
- pSMB->Fid = fid;
- if(SetAllocation) {
- if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
- pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
- else
- pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
- } else /* Set File Size */ {
- if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
- pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
- else
- pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
- }
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1,
- ("Send error in SetFileInfo (SetFileSize) = %d",
- rc));
- }
- if (pSMB)
- cifs_small_buf_release(pSMB);
- /* Note: On -EAGAIN error only caller can retry on handle based calls
- since file handle passed in no longer valid */
- return rc;
- }
- /* Some legacy servers such as NT4 require that the file times be set on
- an open handle, rather than by pathname - this is awkward due to
- potential access conflicts on the open, but it is unavoidable for these
- old servers since the only other choice is to go from 100 nanosecond DCE
- time and resort to the original setpathinfo level which takes the ancient
- DOS time format with 2 second granularity */
- int
- CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
- __u16 fid)
- {
- struct smb_com_transaction2_sfi_req *pSMB = NULL;
- struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
- char *data_offset;
- int rc = 0;
- int bytes_returned = 0;
- __u16 params, param_offset, offset, byte_count, count;
- cFYI(1, ("Set Times (via SetFileInfo)"));
- rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
- if (rc)
- return rc;
- pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
- /* At this point there is no need to override the current pid
- with the pid of the opener, but that could change if we someday
- use an existing handle (rather than opening one on the fly) */
- /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
- pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
-
- params = 6;
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
- offset = param_offset + params;
- data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
- count = sizeof (FILE_BASIC_INFO);
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
- byte_count = 3 /* pad */ + params + count;
- pSMB->DataCount = cpu_to_le16(count);
- pSMB->ParameterCount = cpu_to_le16(params);
- pSMB->TotalDataCount = pSMB->DataCount;
- pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->ParameterOffset = cpu_to_le16(param_offset);
- pSMB->DataOffset = cpu_to_le16(offset);
- pSMB->Fid = fid;
- if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
- pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
- else
- pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
- }
- cifs_small_buf_release(pSMB);
- /* Note: On -EAGAIN error only caller can retry on handle based calls
- since file handle passed in no longer valid */
- return rc;
- }
- int
- CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
- const FILE_BASIC_INFO * data,
- const struct nls_table *nls_codepage, int remap)
- {
- TRANSACTION2_SPI_REQ *pSMB = NULL;
- TRANSACTION2_SPI_RSP *pSMBr = NULL;
- int name_len;
- int rc = 0;
- int bytes_returned = 0;
- char *data_offset;
- __u16 params, param_offset, offset, byte_count, count;
- cFYI(1, ("In SetTimes"));
- SetTimesRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(fileName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, fileName, name_len);
- }
- params = 6 + name_len;
- count = sizeof (FILE_BASIC_INFO);
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
- offset = param_offset + params;
- data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
- pSMB->ParameterOffset = cpu_to_le16(param_offset);
- pSMB->DataOffset = cpu_to_le16(offset);
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
- byte_count = 3 /* pad */ + params + count;
- pSMB->DataCount = cpu_to_le16(count);
- pSMB->ParameterCount = cpu_to_le16(params);
- pSMB->TotalDataCount = pSMB->DataCount;
- pSMB->TotalParameterCount = pSMB->ParameterCount;
- if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
- pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
- else
- pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("SetPathInfo (times) returned %d", rc));
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto SetTimesRetry;
- return rc;
- }
- /* Can not be used to set time stamps yet (due to old DOS time format) */
- /* Can be used to set attributes */
- #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
- handling it anyway and NT4 was what we thought it would be needed for
- Do not delete it until we prove whether needed for Win9x though */
- int
- CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
- __u16 dos_attrs, const struct nls_table *nls_codepage)
- {
- SETATTR_REQ *pSMB = NULL;
- SETATTR_RSP *pSMBr = NULL;
- int rc = 0;
- int bytes_returned;
- int name_len;
- cFYI(1, ("In SetAttrLegacy"));
- SetAttrLgcyRetry:
- rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- ConvertToUCS((__le16 *) pSMB->fileName, fileName,
- PATH_MAX, nls_codepage);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(fileName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->fileName, fileName, name_len);
- }
- pSMB->attr = cpu_to_le16(dos_attrs);
- pSMB->BufferFormat = 0x04;
- pSMB->hdr.smb_buf_length += name_len + 1;
- pSMB->ByteCount = cpu_to_le16(name_len + 1);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Error in LegacySetAttr = %d", rc));
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto SetAttrLgcyRetry;
- return rc;
- }
- #endif /* temporarily unneeded SetAttr legacy function */
- int
- CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
- char *fileName, __u64 mode, __u64 uid, __u64 gid,
- dev_t device, const struct nls_table *nls_codepage,
- int remap)
- {
- TRANSACTION2_SPI_REQ *pSMB = NULL;
- TRANSACTION2_SPI_RSP *pSMBr = NULL;
- int name_len;
- int rc = 0;
- int bytes_returned = 0;
- FILE_UNIX_BASIC_INFO *data_offset;
- __u16 params, param_offset, offset, count, byte_count;
- cFYI(1, ("In SetUID/GID/Mode"));
- setPermsRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(fileName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, fileName, name_len);
- }
- params = 6 + name_len;
- count = sizeof (FILE_UNIX_BASIC_INFO);
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
- offset = param_offset + params;
- data_offset =
- (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
- offset);
- memset(data_offset, 0, count);
- pSMB->DataOffset = cpu_to_le16(offset);
- pSMB->ParameterOffset = cpu_to_le16(param_offset);
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
- byte_count = 3 /* pad */ + params + count;
- pSMB->ParameterCount = cpu_to_le16(params);
- pSMB->DataCount = cpu_to_le16(count);
- pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->TotalDataCount = pSMB->DataCount;
- pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- data_offset->Uid = cpu_to_le64(uid);
- data_offset->Gid = cpu_to_le64(gid);
- /* better to leave device as zero when it is */
- data_offset->DevMajor = cpu_to_le64(MAJOR(device));
- data_offset->DevMinor = cpu_to_le64(MINOR(device));
- data_offset->Permissions = cpu_to_le64(mode);
-
- if(S_ISREG(mode))
- data_offset->Type = cpu_to_le32(UNIX_FILE);
- else if(S_ISDIR(mode))
- data_offset->Type = cpu_to_le32(UNIX_DIR);
- else if(S_ISLNK(mode))
- data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
- else if(S_ISCHR(mode))
- data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
- else if(S_ISBLK(mode))
- data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
- else if(S_ISFIFO(mode))
- data_offset->Type = cpu_to_le32(UNIX_FIFO);
- else if(S_ISSOCK(mode))
- data_offset->Type = cpu_to_le32(UNIX_SOCKET);
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("SetPathInfo (perms) returned %d", rc));
- }
- if (pSMB)
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto setPermsRetry;
- return rc;
- }
- int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
- const int notify_subdirs, const __u16 netfid,
- __u32 filter, struct file * pfile, int multishot,
- const struct nls_table *nls_codepage)
- {
- int rc = 0;
- struct smb_com_transaction_change_notify_req * pSMB = NULL;
- struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
- struct dir_notify_req *dnotify_req;
- int bytes_returned;
- cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
- rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- pSMB->TotalParameterCount = 0 ;
- pSMB->TotalDataCount = 0;
- pSMB->MaxParameterCount = cpu_to_le32(2);
- /* BB find exact data count max from sess structure BB */
- pSMB->MaxDataCount = 0; /* same in little endian or be */
- /* BB VERIFY verify which is correct for above BB */
- pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
- MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
- pSMB->MaxSetupCount = 4;
- pSMB->Reserved = 0;
- pSMB->ParameterOffset = 0;
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 4; /* single byte does not need le conversion */
- pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- if(notify_subdirs)
- pSMB->WatchTree = 1; /* one byte - no le conversion needed */
- pSMB->Reserved2 = 0;
- pSMB->CompletionFilter = cpu_to_le32(filter);
- pSMB->Fid = netfid; /* file handle always le */
- pSMB->ByteCount = 0;
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, -1);
- if (rc) {
- cFYI(1, ("Error in Notify = %d", rc));
- } else {
- /* Add file to outstanding requests */
- /* BB change to kmem cache alloc */
- dnotify_req = (struct dir_notify_req *) kmalloc(
- sizeof(struct dir_notify_req),
- GFP_KERNEL);
- if(dnotify_req) {
- dnotify_req->Pid = pSMB->hdr.Pid;
- dnotify_req->PidHigh = pSMB->hdr.PidHigh;
- dnotify_req->Mid = pSMB->hdr.Mid;
- dnotify_req->Tid = pSMB->hdr.Tid;
- dnotify_req->Uid = pSMB->hdr.Uid;
- dnotify_req->netfid = netfid;
- dnotify_req->pfile = pfile;
- dnotify_req->filter = filter;
- dnotify_req->multishot = multishot;
- spin_lock(&GlobalMid_Lock);
- list_add_tail(&dnotify_req->lhead,
- &GlobalDnotifyReqList);
- spin_unlock(&GlobalMid_Lock);
- } else
- rc = -ENOMEM;
- }
- cifs_buf_release(pSMB);
- return rc;
- }
- #ifdef CONFIG_CIFS_XATTR
- ssize_t
- CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *searchName,
- char * EAData, size_t buf_size,
- const struct nls_table *nls_codepage, int remap)
- {
- /* BB assumes one setup word */
- TRANSACTION2_QPI_REQ *pSMB = NULL;
- TRANSACTION2_QPI_RSP *pSMBr = NULL;
- int rc = 0;
- int bytes_returned;
- int name_len;
- struct fea * temp_fea;
- char * temp_ptr;
- __u16 params, byte_count;
- cFYI(1, ("In Query All EAs path %s", searchName));
- QAllEAsRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(searchName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, searchName, name_len);
- }
- params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
- pSMB->TotalDataCount = 0;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
- byte_count = params + 1 /* pad */ ;
- pSMB->TotalParameterCount = cpu_to_le16(params);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Send error in QueryAllEAs = %d", rc));
- } else { /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- /* BB also check enough total bytes returned */
- /* BB we need to improve the validity checking
- of these trans2 responses */
- if (rc || (pSMBr->ByteCount < 4))
- rc = -EIO; /* bad smb */
- /* else if (pFindData){
- memcpy((char *) pFindData,
- (char *) &pSMBr->hdr.Protocol +
- data_offset, kl);
- }*/ else {
- /* check that length of list is not more than bcc */
- /* check that each entry does not go beyond length
- of list */
- /* check that each element of each entry does not
- go beyond end of list */
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- struct fealist * ea_response_data;
- rc = 0;
- /* validate_trans2_offsets() */
- /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
- ea_response_data = (struct fealist *)
- (((char *) &pSMBr->hdr.Protocol) +
- data_offset);
- name_len = le32_to_cpu(ea_response_data->list_len);
- cFYI(1,("ea length %d", name_len));
- if(name_len <= 8) {
- /* returned EA size zeroed at top of function */
- cFYI(1,("empty EA list returned from server"));
- } else {
- /* account for ea list len */
- name_len -= 4;
- temp_fea = ea_response_data->list;
- temp_ptr = (char *)temp_fea;
- while(name_len > 0) {
- __u16 value_len;
- name_len -= 4;
- temp_ptr += 4;
- rc += temp_fea->name_len;
- /* account for prefix user. and trailing null */
- rc = rc + 5 + 1;
- if(rc<(int)buf_size) {
- memcpy(EAData,"user.",5);
- EAData+=5;
- memcpy(EAData,temp_ptr,temp_fea->name_len);
- EAData+=temp_fea->name_len;
- /* null terminate name */
- *EAData = 0;
- EAData = EAData + 1;
- } else if(buf_size == 0) {
- /* skip copy - calc size only */
- } else {
- /* stop before overrun buffer */
- rc = -ERANGE;
- break;
- }
- name_len -= temp_fea->name_len;
- temp_ptr += temp_fea->name_len;
- /* account for trailing null */
- name_len--;
- temp_ptr++;
- value_len = le16_to_cpu(temp_fea->value_len);
- name_len -= value_len;
- temp_ptr += value_len;
- /* BB check that temp_ptr is still within smb BB*/
- /* no trailing null to account for in value len */
- /* go on to next EA */
- temp_fea = (struct fea *)temp_ptr;
- }
- }
- }
- }
- if (pSMB)
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto QAllEAsRetry;
- return (ssize_t)rc;
- }
- ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
- const unsigned char * searchName,const unsigned char * ea_name,
- unsigned char * ea_value, size_t buf_size,
- const struct nls_table *nls_codepage, int remap)
- {
- TRANSACTION2_QPI_REQ *pSMB = NULL;
- TRANSACTION2_QPI_RSP *pSMBr = NULL;
- int rc = 0;
- int bytes_returned;
- int name_len;
- struct fea * temp_fea;
- char * temp_ptr;
- __u16 params, byte_count;
- cFYI(1, ("In Query EA path %s", searchName));
- QEARetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(searchName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, searchName, name_len);
- }
- params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
- pSMB->TotalDataCount = 0;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
- byte_count = params + 1 /* pad */ ;
- pSMB->TotalParameterCount = cpu_to_le16(params);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("Send error in Query EA = %d", rc));
- } else { /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- /* BB also check enough total bytes returned */
- /* BB we need to improve the validity checking
- of these trans2 responses */
- if (rc || (pSMBr->ByteCount < 4))
- rc = -EIO; /* bad smb */
- /* else if (pFindData){
- memcpy((char *) pFindData,
- (char *) &pSMBr->hdr.Protocol +
- data_offset, kl);
- }*/ else {
- /* check that length of list is not more than bcc */
- /* check that each entry does not go beyond length
- of list */
- /* check that each element of each entry does not
- go beyond end of list */
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- struct fealist * ea_response_data;
- rc = -ENODATA;
- /* validate_trans2_offsets() */
- /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
- ea_response_data = (struct fealist *)
- (((char *) &pSMBr->hdr.Protocol) +
- data_offset);
- name_len = le32_to_cpu(ea_response_data->list_len);
- cFYI(1,("ea length %d", name_len));
- if(name_len <= 8) {
- /* returned EA size zeroed at top of function */
- cFYI(1,("empty EA list returned from server"));
- } else {
- /* account for ea list len */
- name_len -= 4;
- temp_fea = ea_response_data->list;
- temp_ptr = (char *)temp_fea;
- /* loop through checking if we have a matching
- name and then return the associated value */
- while(name_len > 0) {
- __u16 value_len;
- name_len -= 4;
- temp_ptr += 4;
- value_len = le16_to_cpu(temp_fea->value_len);
- /* BB validate that value_len falls within SMB,
- even though maximum for name_len is 255 */
- if(memcmp(temp_fea->name,ea_name,
- temp_fea->name_len) == 0) {
- /* found a match */
- rc = value_len;
- /* account for prefix user. and trailing null */
- if(rc<=(int)buf_size) {
- memcpy(ea_value,
- temp_fea->name+temp_fea->name_len+1,
- rc);
- /* ea values, unlike ea names,
- are not null terminated */
- } else if(buf_size == 0) {
- /* skip copy - calc size only */
- } else {
- /* stop before overrun buffer */
- rc = -ERANGE;
- }
- break;
- }
- name_len -= temp_fea->name_len;
- temp_ptr += temp_fea->name_len;
- /* account for trailing null */
- name_len--;
- temp_ptr++;
- name_len -= value_len;
- temp_ptr += value_len;
- /* no trailing null to account for in value len */
- /* go on to next EA */
- temp_fea = (struct fea *)temp_ptr;
- }
- }
- }
- }
- if (pSMB)
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto QEARetry;
- return (ssize_t)rc;
- }
- int
- CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
- const char * ea_name, const void * ea_value,
- const __u16 ea_value_len, const struct nls_table *nls_codepage,
- int remap)
- {
- struct smb_com_transaction2_spi_req *pSMB = NULL;
- struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
- struct fealist *parm_data;
- int name_len;
- int rc = 0;
- int bytes_returned = 0;
- __u16 params, param_offset, byte_count, offset, count;
- cFYI(1, ("In SetEA"));
- SetEARetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
- if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
- PATH_MAX, nls_codepage, remap);
- name_len++; /* trailing null */
- name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(fileName, PATH_MAX);
- name_len++; /* trailing null */
- strncpy(pSMB->FileName, fileName, name_len);
- }
- params = 6 + name_len;
- /* done calculating parms using name_len of file name,
- now use name_len to calculate length of ea name
- we are going to create in the inode xattrs */
- if(ea_name == NULL)
- name_len = 0;
- else
- name_len = strnlen(ea_name,255);
- count = sizeof(*parm_data) + ea_value_len + name_len + 1;
- pSMB->MaxParameterCount = cpu_to_le16(2);
- pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
- pSMB->MaxSetupCount = 0;
- pSMB->Reserved = 0;
- pSMB->Flags = 0;
- pSMB->Timeout = 0;
- pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
- offset = param_offset + params;
- pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_EA);
- parm_data =
- (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
- offset);
- pSMB->ParameterOffset = cpu_to_le16(param_offset);
- pSMB->DataOffset = cpu_to_le16(offset);
- pSMB->SetupCount = 1;
- pSMB->Reserved3 = 0;
- pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
- byte_count = 3 /* pad */ + params + count;
- pSMB->DataCount = cpu_to_le16(count);
- parm_data->list_len = cpu_to_le32(count);
- parm_data->list[0].EA_flags = 0;
- /* we checked above that name len is less than 255 */
- parm_data->list[0].name_len = (__u8)name_len;;
- /* EA names are always ASCII */
- if(ea_name)
- strncpy(parm_data->list[0].name,ea_name,name_len);
- parm_data->list[0].name[name_len] = 0;
- parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
- /* caller ensures that ea_value_len is less than 64K but
- we need to ensure that it fits within the smb */
- /*BB add length check that it would fit in negotiated SMB buffer size BB */
- /* if(ea_value_len > buffer_size - 512 (enough for header)) */
- if(ea_value_len)
- memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
- pSMB->TotalDataCount = pSMB->DataCount;
- pSMB->ParameterCount = cpu_to_le16(params);
- pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->ByteCount = cpu_to_le16(byte_count);
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("SetPathInfo (EA) returned %d", rc));
- }
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto SetEARetry;
- return rc;
- }
- #endif
|