proto.c 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <ip.h>
  5. #include <auth.h>
  6. #include <fcall.h>
  7. #include <ctype.h>
  8. #include <String.h>
  9. #include "ftpfs.h"
  10. enum
  11. {
  12. /* return codes */
  13. Extra= 1,
  14. Success= 2,
  15. Incomplete= 3,
  16. TempFail= 4,
  17. PermFail= 5,
  18. Impossible= 6,
  19. };
  20. Node *remdir; /* current directory on remote machine */
  21. Node *remroot; /* root directory on remote machine */
  22. int ctlfd; /* fd for control connection */
  23. Biobuf ctlin; /* input buffer for control connection */
  24. Biobuf stdin; /* input buffer for standard input */
  25. Biobuf dbuf; /* buffer for data connection */
  26. char msg[512]; /* buffer for replies */
  27. char net[Maxpath]; /* network for connections */
  28. int listenfd; /* fd to listen on for connections */
  29. char netdir[Maxpath];
  30. int os, defos;
  31. char topsdir[64]; /* name of listed directory for TOPS */
  32. String *remrootpath; /* path on remote side to remote root */
  33. char *user;
  34. int nopassive;
  35. long lastsend;
  36. static void sendrequest(char*, char*);
  37. static int getreply(Biobuf*, char*, int, int);
  38. static int active(int, Biobuf**, char*, char*);
  39. static int passive(int, Biobuf**, char*, char*);
  40. static int data(int, Biobuf**, char*, char*);
  41. static int port(void);
  42. static void ascii(void);
  43. static void image(void);
  44. static void unixpath(Node*, String*);
  45. static void vmspath(Node*, String*);
  46. static void mvspath(Node*, String*);
  47. static Node* vmsdir(char*);
  48. static int getpassword(char*, char*);
  49. static int nw_mode(char dirlet, char *s);
  50. /*
  51. * connect to remote server, default network is "tcp/ip"
  52. */
  53. void
  54. hello(char *dest)
  55. {
  56. char *p;
  57. char dir[Maxpath];
  58. Binit(&stdin, 0, OREAD); /* init for later use */
  59. ctlfd = dial(netmkaddr(dest, "tcp", "ftp"), 0, dir, 0);
  60. if(ctlfd < 0){
  61. fprint(2, "can't dial %s: %r\n", dest);
  62. exits("dialing");
  63. }
  64. Binit(&ctlin, ctlfd, OREAD);
  65. /* remember network for the data connections */
  66. p = strrchr(dir+1, '/');
  67. if(p == 0)
  68. fatal("wrong dial(2) linked with ftp");
  69. *p = 0;
  70. safecpy(net, dir, sizeof(net));
  71. /* wait for hello from other side */
  72. if(getreply(&ctlin, msg, sizeof(msg), 1) != Success)
  73. fatal("bad hello");
  74. if(strstr(msg, "Plan 9"))
  75. os = Plan9;
  76. }
  77. /*
  78. * login to remote system
  79. */
  80. void
  81. rlogin(char *rsys, char *keyspec)
  82. {
  83. char *line;
  84. char pass[128];
  85. UserPasswd *up;
  86. up = nil;
  87. for(;;){
  88. if(up == nil && os != Plan9)
  89. up = auth_getuserpasswd(auth_getkey, "proto=pass server=%s service=ftp %s", rsys, keyspec);
  90. if(up != nil){
  91. sendrequest("USER", up->user);
  92. } else {
  93. print("User[default = %s]: ", user);
  94. line = Brdline(&stdin, '\n');
  95. if(line == 0)
  96. exits(0);
  97. line[Blinelen(&stdin)-1] = 0;
  98. if(*line){
  99. free(user);
  100. user = strdup(line);
  101. }
  102. sendrequest("USER", user);
  103. }
  104. switch(getreply(&ctlin, msg, sizeof(msg), 1)){
  105. case Success:
  106. goto out;
  107. case Incomplete:
  108. break;
  109. case TempFail:
  110. case PermFail:
  111. continue;
  112. }
  113. if(up != nil){
  114. sendrequest("PASS", up->passwd);
  115. } else {
  116. if(getpassword(pass, pass+sizeof(pass)) < 0)
  117. exits(0);
  118. sendrequest("PASS", pass);
  119. }
  120. if(getreply(&ctlin, msg, sizeof(msg), 1) == Success){
  121. if(strstr(msg, "Sess#"))
  122. defos = MVS;
  123. break;
  124. }
  125. }
  126. out:
  127. if(up != nil){
  128. memset(up, 0, sizeof(*up));
  129. free(up);
  130. }
  131. }
  132. /*
  133. * login to remote system with given user name and password.
  134. */
  135. void
  136. clogin(char *cuser, char *cpassword)
  137. {
  138. free(user);
  139. user = strdup(cuser);
  140. if (strcmp(user, "anonymous") != 0 &&
  141. strcmp(user, "ftp") != 0)
  142. fatal("User must be 'anonymous' or 'ftp'");
  143. sendrequest("USER", user);
  144. switch(getreply(&ctlin, msg, sizeof(msg), 1)){
  145. case Success:
  146. return;
  147. case Incomplete:
  148. break;
  149. case TempFail:
  150. case PermFail:
  151. fatal("login failed");
  152. }
  153. if (cpassword == 0)
  154. fatal("password needed");
  155. sendrequest("PASS", cpassword);
  156. if(getreply(&ctlin, msg, sizeof(msg), 1) != Success)
  157. fatal("password failed");
  158. if(strstr(msg, "Sess#"))
  159. defos = MVS;
  160. return;
  161. }
  162. /*
  163. * find out about the other side. go to it's root if requested. set
  164. * image mode if a Plan9 system.
  165. */
  166. void
  167. preamble(char *mountroot)
  168. {
  169. char *p, *ep;
  170. int rv;
  171. OS *o;
  172. /*
  173. * create a root directory mirror
  174. */
  175. remroot = newnode(0, s_copy("/"));
  176. remroot->d->qid.type = QTDIR;
  177. remroot->d->mode = DMDIR|0777;
  178. remdir = remroot;
  179. /*
  180. * get system type
  181. */
  182. sendrequest("SYST", nil);
  183. switch(getreply(&ctlin, msg, sizeof(msg), 1)){
  184. case Success:
  185. for(o = oslist; o->os != Unknown; o++)
  186. if(strncmp(msg+4, o->name, strlen(o->name)) == 0)
  187. break;
  188. os = o->os;
  189. if(os == NT)
  190. os = Unix;
  191. break;
  192. default:
  193. os = defos;
  194. break;
  195. }
  196. if(os == Unknown)
  197. os = defos;
  198. remrootpath = s_reset(remrootpath);
  199. switch(os){
  200. case NetWare:
  201. /*
  202. * Request long, rather than 8.3 filenames,
  203. * where the Servers & Volume support them.
  204. */
  205. sendrequest("SITE LONG", nil);
  206. getreply(&ctlin, msg, sizeof(msg), 0);
  207. /* FALL THRU */
  208. case Unix:
  209. case Plan9:
  210. /*
  211. * go to the remote root, if asked
  212. */
  213. if(mountroot){
  214. sendrequest("CWD", mountroot);
  215. getreply(&ctlin, msg, sizeof(msg), 0);
  216. } else {
  217. s_append(remrootpath, "/usr/");
  218. s_append(remrootpath, user);
  219. }
  220. /*
  221. * get the root directory
  222. */
  223. sendrequest("PWD", nil);
  224. rv = getreply(&ctlin, msg, sizeof(msg), 1);
  225. if(rv == PermFail){
  226. sendrequest("XPWD", nil);
  227. rv = getreply(&ctlin, msg, sizeof(msg), 1);
  228. }
  229. if(rv == Success){
  230. p = strchr(msg, '"');
  231. if(p){
  232. p++;
  233. ep = strchr(p, '"');
  234. if(ep){
  235. *ep = 0;
  236. s_append(s_reset(remrootpath), p);
  237. }
  238. }
  239. }
  240. break;
  241. case Tops:
  242. case VM:
  243. /*
  244. * top directory is a figment of our imagination.
  245. * make it permanently cached & valid.
  246. */
  247. CACHED(remroot);
  248. VALID(remroot);
  249. remroot->d->atime = time(0) + 100000;
  250. /*
  251. * no initial directory. We are in the
  252. * imaginary root.
  253. */
  254. remdir = newtopsdir("???");
  255. topsdir[0] = 0;
  256. if(os == Tops && readdir(remdir) >= 0){
  257. CACHED(remdir);
  258. if(*topsdir)
  259. remdir->remname = s_copy(topsdir);
  260. VALID(remdir);
  261. }
  262. break;
  263. case VMS:
  264. /*
  265. * top directory is a figment of our imagination.
  266. * make it permanently cached & valid.
  267. */
  268. CACHED(remroot);
  269. VALID(remroot);
  270. remroot->d->atime = time(0) + 100000;
  271. /*
  272. * get current directory
  273. */
  274. sendrequest("PWD", nil);
  275. rv = getreply(&ctlin, msg, sizeof(msg), 1);
  276. if(rv == PermFail){
  277. sendrequest("XPWD", nil);
  278. rv = getreply(&ctlin, msg, sizeof(msg), 1);
  279. }
  280. if(rv == Success){
  281. p = strchr(msg, '"');
  282. if(p){
  283. p++;
  284. ep = strchr(p, '"');
  285. if(ep){
  286. *ep = 0;
  287. remroot = remdir = vmsdir(p);
  288. }
  289. }
  290. }
  291. break;
  292. case MVS:
  293. usenlst = 1;
  294. break;
  295. }
  296. if(os == Plan9)
  297. image();
  298. }
  299. static void
  300. ascii(void)
  301. {
  302. sendrequest("TYPE A", nil);
  303. switch(getreply(&ctlin, msg, sizeof(msg), 0)){
  304. case Success:
  305. break;
  306. default:
  307. fatal("can't set type to ascii");
  308. }
  309. }
  310. static void
  311. image(void)
  312. {
  313. sendrequest("TYPE I", nil);
  314. switch(getreply(&ctlin, msg, sizeof(msg), 0)){
  315. case Success:
  316. break;
  317. default:
  318. fatal("can't set type to image/binary");
  319. }
  320. }
  321. /*
  322. * decode the time fields, return seconds since epoch began
  323. */
  324. char *monthchars = "janfebmaraprmayjunjulaugsepoctnovdec";
  325. static Tm now;
  326. static ulong
  327. cracktime(char *month, char *day, char *yr, char *hms)
  328. {
  329. Tm tm;
  330. int i;
  331. char *p;
  332. /* default time */
  333. if(now.year == 0)
  334. now = *localtime(time(0));
  335. tm = now;
  336. tm.yday = 0;
  337. /* convert ascii month to a number twixt 1 and 12 */
  338. if(*month >= '0' && *month <= '9'){
  339. tm.mon = atoi(month) - 1;
  340. if(tm.mon < 0 || tm.mon > 11)
  341. tm.mon = 5;
  342. } else {
  343. for(p = month; *p; p++)
  344. *p = tolower(*p);
  345. for(i = 0; i < 12; i++)
  346. if(strncmp(&monthchars[i*3], month, 3) == 0){
  347. tm.mon = i;
  348. break;
  349. }
  350. }
  351. tm.mday = atoi(day);
  352. if(hms){
  353. tm.hour = strtol(hms, &p, 0);
  354. if(*p == ':'){
  355. tm.min = strtol(p+1, &p, 0);
  356. if(*p == ':')
  357. tm.sec = strtol(p+1, &p, 0);
  358. }
  359. if(tolower(*p) == 'p')
  360. tm.hour += 12;
  361. }
  362. if(yr){
  363. tm.year = atoi(yr);
  364. if(tm.year >= 1900)
  365. tm.year -= 1900;
  366. } else {
  367. if(tm.mon > now.mon || (tm.mon == now.mon && tm.mday > now.mday+1))
  368. tm.year--;
  369. }
  370. /* convert to epoch seconds */
  371. return tm2sec(&tm);
  372. }
  373. /*
  374. * decode a Unix or Plan 9 file mode
  375. */
  376. static ulong
  377. crackmode(char *p)
  378. {
  379. ulong flags;
  380. ulong mode;
  381. int i;
  382. flags = 0;
  383. switch(strlen(p)){
  384. case 10: /* unix and new style plan 9 */
  385. switch(*p){
  386. case 'l':
  387. return DMSYML|0777;
  388. case 'd':
  389. flags |= DMDIR;
  390. case 'a':
  391. flags |= DMAPPEND;
  392. }
  393. p++;
  394. if(p[2] == 'l')
  395. flags |= DMEXCL;
  396. break;
  397. case 11: /* old style plan 9 */
  398. switch(*p++){
  399. case 'd':
  400. flags |= DMDIR;
  401. break;
  402. case 'a':
  403. flags |= DMAPPEND;
  404. break;
  405. }
  406. if(*p++ == 'l')
  407. flags |= DMEXCL;
  408. break;
  409. default:
  410. return DMDIR|0777;
  411. }
  412. mode = 0;
  413. for(i = 0; i < 3; i++){
  414. mode <<= 3;
  415. if(*p++ == 'r')
  416. mode |= DMREAD;
  417. if(*p++ == 'w')
  418. mode |= DMWRITE;
  419. if(*p == 'x' || *p == 's' || *p == 'S')
  420. mode |= DMEXEC;
  421. p++;
  422. }
  423. return mode | flags;
  424. }
  425. /*
  426. * find first punctuation
  427. */
  428. char*
  429. strpunct(char *p)
  430. {
  431. int c;
  432. for(;c = *p; p++){
  433. if(ispunct(c))
  434. return p;
  435. }
  436. return 0;
  437. }
  438. /*
  439. * decode a Unix or Plan 9 directory listing
  440. */
  441. static Dir*
  442. crackdir(char *p, String **remname)
  443. {
  444. char *field[15];
  445. char *dfield[4];
  446. char *cp;
  447. String *s;
  448. int dn, n;
  449. Dir d, *dp;
  450. memset(&d, 0, sizeof(d));
  451. n = getfields(p, field, 15, 1, " \t");
  452. if(n > 2 && strcmp(field[n-2], "->") == 0)
  453. n -= 2;
  454. switch(os){
  455. case TSO:
  456. cp = strchr(field[0], '.');
  457. if(cp){
  458. *cp++ = 0;
  459. s = s_copy(cp);
  460. d.uid = field[0];
  461. } else {
  462. s = s_copy(field[0]);
  463. d.uid = "TSO";
  464. }
  465. d.gid = "TSO";
  466. d.mode = 0666;
  467. d.length = 0;
  468. d.atime = 0;
  469. break;
  470. case OS½:
  471. s = s_copy(field[n-1]);
  472. d.uid = "OS½";
  473. d.gid = d.uid;
  474. d.mode = 0666;
  475. switch(n){
  476. case 5:
  477. if(strcmp(field[1], "DIR") == 0)
  478. d.mode |= DMDIR;
  479. d.length = atoi(field[0]);
  480. dn = getfields(field[2], dfield, 4, 1, "-");
  481. if(dn == 3)
  482. d.atime = cracktime(dfield[0], dfield[1], dfield[2], field[3]);
  483. break;
  484. }
  485. break;
  486. case Tops:
  487. if(n != 4){ /* tops directory name */
  488. safecpy(topsdir, field[0], sizeof(topsdir));
  489. return 0;
  490. }
  491. s = s_copy(field[3]);
  492. d.length = atoi(field[0]);
  493. d.mode = 0666;
  494. d.uid = "Tops";
  495. d.gid = d.uid;
  496. dn = getfields(field[1], dfield, 4, 1, "-");
  497. if(dn == 3)
  498. d.atime = cracktime(dfield[1], dfield[0], dfield[2], field[2]);
  499. else
  500. d.atime = time(0);
  501. break;
  502. case VM:
  503. switch(n){
  504. case 9:
  505. s = s_copy(field[0]);
  506. s_append(s, ".");
  507. s_append(s, field[1]);
  508. d.length = atoi(field[3])*atoi(field[4]);
  509. if(*field[2] == 'F')
  510. d.mode = 0666;
  511. else
  512. d.mode = 0777;
  513. d.uid = "VM";
  514. d.gid = d.uid;
  515. dn = getfields(field[6], dfield, 4, 1, "/-");
  516. if(dn == 3)
  517. d.atime = cracktime(dfield[0], dfield[1], dfield[2], field[7]);
  518. else
  519. d.atime = time(0);
  520. break;
  521. case 1:
  522. s = s_copy(field[0]);
  523. d.uid = "VM";
  524. d.gid = d.uid;
  525. d.mode = 0777;
  526. d.atime = 0;
  527. break;
  528. default:
  529. return nil;
  530. }
  531. break;
  532. case VMS:
  533. switch(n){
  534. case 6:
  535. for(cp = field[0]; *cp; cp++)
  536. *cp = tolower(*cp);
  537. cp = strchr(field[0], ';');
  538. if(cp)
  539. *cp = 0;
  540. d.mode = 0666;
  541. cp = field[0] + strlen(field[0]) - 4;
  542. if(strcmp(cp, ".dir") == 0){
  543. d.mode |= DMDIR;
  544. *cp = 0;
  545. }
  546. s = s_copy(field[0]);
  547. d.length = atoi(field[1])*512;
  548. field[4][strlen(field[4])-1] = 0;
  549. d.uid = field[4]+1;
  550. d.gid = d.uid;
  551. dn = getfields(field[2], dfield, 4, 1, "/-");
  552. if(dn == 3)
  553. d.atime = cracktime(dfield[1], dfield[0], dfield[2], field[3]);
  554. else
  555. d.atime = time(0);
  556. break;
  557. default:
  558. return nil;
  559. }
  560. break;
  561. case NetWare:
  562. switch(n){
  563. case 8: /* New style */
  564. s = s_copy(field[7]);
  565. d.uid = field[2];
  566. d.gid = d.uid;
  567. d.mode = nw_mode(field[0][0], field[1]);
  568. d.length = atoi(field[3]);
  569. if(strchr(field[6], ':'))
  570. d.atime = cracktime(field[4], field[5], nil, field[6]);
  571. else
  572. d.atime = cracktime(field[4], field[5], field[6], nil);
  573. break;
  574. case 9:
  575. s = s_copy(field[8]);
  576. d.uid = field[2];
  577. d.gid = d.uid;
  578. d.mode = 0666;
  579. if(*field[0] == 'd')
  580. d.mode |= DMDIR;
  581. d.length = atoi(field[3]);
  582. d.atime = cracktime(field[4], field[5], field[6], field[7]);
  583. break;
  584. case 1:
  585. s = s_copy(field[0]);
  586. d.uid = "none";
  587. d.gid = d.uid;
  588. d.mode = 0777;
  589. d.atime = 0;
  590. break;
  591. default:
  592. return nil;
  593. }
  594. break;
  595. case Unix:
  596. case Plan9:
  597. default:
  598. switch(n){
  599. case 8: /* ls -l */
  600. s = s_copy(field[7]);
  601. d.uid = field[2];
  602. d.gid = d.uid;
  603. d.mode = crackmode(field[0]);
  604. d.length = atoi(field[3]);
  605. if(strchr(field[6], ':'))
  606. d.atime = cracktime(field[4], field[5], 0, field[6]);
  607. else
  608. d.atime = cracktime(field[4], field[5], field[6], 0);
  609. break;
  610. case 9: /* ls -lg */
  611. s = s_copy(field[8]);
  612. d.uid = field[2];
  613. d.gid = field[3];
  614. d.mode = crackmode(field[0]);
  615. d.length = atoi(field[4]);
  616. if(strchr(field[7], ':'))
  617. d.atime = cracktime(field[5], field[6], 0, field[7]);
  618. else
  619. d.atime = cracktime(field[5], field[6], field[7], 0);
  620. break;
  621. case 10: /* plan 9 */
  622. s = s_copy(field[9]);
  623. d.uid = field[3];
  624. d.gid = field[4];
  625. d.mode = crackmode(field[0]);
  626. d.length = atoi(field[5]);
  627. if(strchr(field[8], ':'))
  628. d.atime = cracktime(field[6], field[7], 0, field[8]);
  629. else
  630. d.atime = cracktime(field[6], field[7], field[8], 0);
  631. break;
  632. case 4: /* a Windows_NT version */
  633. s = s_copy(field[3]);
  634. d.uid = "NT";
  635. d.gid = d.uid;
  636. if(strcmp("<DIR>", field[2]) == 0){
  637. d.length = 0;
  638. d.mode = DMDIR|0777;
  639. } else {
  640. d.mode = 0666;
  641. d.length = atoi(field[2]);
  642. }
  643. dn = getfields(field[0], dfield, 4, 1, "/-");
  644. if(dn == 3)
  645. d.atime = cracktime(dfield[0], dfield[1], dfield[2], field[1]);
  646. break;
  647. case 1:
  648. s = s_copy(field[0]);
  649. d.uid = "none";
  650. d.gid = d.uid;
  651. d.mode = 0777;
  652. d.atime = 0;
  653. break;
  654. default:
  655. return nil;
  656. }
  657. }
  658. d.muid = d.uid;
  659. d.qid.type = (d.mode & DMDIR) ? QTDIR : QTFILE;
  660. d.mtime = d.atime;
  661. if(ext && (d.qid.type & QTDIR) == 0)
  662. s_append(s, ext);
  663. d.name = s_to_c(s);
  664. /* allocate a freeable dir structure */
  665. dp = reallocdir(&d, 0);
  666. *remname = s;
  667. return dp;
  668. }
  669. /*
  670. * probe files in a directory to see if they are directories
  671. */
  672. /*
  673. * read a remote directory
  674. */
  675. int
  676. readdir(Node *node)
  677. {
  678. Biobuf *bp;
  679. char *line;
  680. Node *np;
  681. Dir *d;
  682. long n;
  683. int tries, x, files;
  684. static int uselist;
  685. int usenlist;
  686. String *remname;
  687. if(changedir(node) < 0)
  688. return -1;
  689. usenlist = 0;
  690. for(tries = 0; tries < 3; tries++){
  691. if(usenlist || usenlst)
  692. x = data(OREAD, &bp, "NLST", nil);
  693. else if(os == Unix && !uselist)
  694. x = data(OREAD, &bp, "LIST -l", nil);
  695. else
  696. x = data(OREAD, &bp, "LIST", nil);
  697. switch(x){
  698. case Extra:
  699. break;
  700. /* case TempFail:
  701. continue;
  702. */
  703. default:
  704. if(os == Unix && uselist == 0){
  705. uselist = 1;
  706. continue;
  707. }
  708. return seterr(nosuchfile);
  709. }
  710. files = 0;
  711. while(line = Brdline(bp, '\n')){
  712. n = Blinelen(bp);
  713. if(debug)
  714. write(2, line, n);
  715. if(n > 1 && line[n-2] == '\r')
  716. n--;
  717. line[n - 1] = 0;
  718. d = crackdir(line, &remname);
  719. if(d == nil)
  720. continue;
  721. files++;
  722. np = extendpath(node, remname);
  723. d->qid.path = np->d->qid.path;
  724. d->qid.vers = np->d->qid.vers;
  725. d->type = np->d->type;
  726. d->dev = 1; /* mark node as valid */
  727. if(os == MVS && node == remroot){
  728. d->qid.type = QTDIR;
  729. d->mode |= DMDIR;
  730. }
  731. free(np->d);
  732. np->d = d;
  733. }
  734. close(Bfildes(bp));
  735. switch(getreply(&ctlin, msg, sizeof(msg), 0)){
  736. case Success:
  737. if(files == 0 && !usenlst && !usenlist){
  738. usenlist = 1;
  739. continue;
  740. }
  741. if(files && usenlist)
  742. usenlst = 1;
  743. if(usenlst)
  744. node->chdirunknown = 1;
  745. return 0;
  746. case TempFail:
  747. break;
  748. default:
  749. return seterr(nosuchfile);
  750. }
  751. }
  752. return seterr(nosuchfile);
  753. }
  754. /*
  755. * create a remote directory
  756. */
  757. int
  758. createdir(Node *node)
  759. {
  760. if(changedir(node->parent) < 0)
  761. return -1;
  762. sendrequest("MKD", node->d->name);
  763. if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)
  764. return -1;
  765. return 0;
  766. }
  767. /*
  768. * change to a remote directory.
  769. */
  770. int
  771. changedir(Node *node)
  772. {
  773. Node *to;
  774. String *cdpath;
  775. to = node;
  776. if(to == remdir)
  777. return 0;
  778. /* build an absolute path */
  779. switch(os){
  780. case Tops:
  781. case VM:
  782. switch(node->depth){
  783. case 0:
  784. remdir = node;
  785. return 0;
  786. case 1:
  787. cdpath = s_clone(node->remname);
  788. break;
  789. default:
  790. return seterr(nosuchfile);
  791. }
  792. break;
  793. case VMS:
  794. switch(node->depth){
  795. case 0:
  796. remdir = node;
  797. return 0;
  798. default:
  799. cdpath = s_new();
  800. vmspath(node, cdpath);
  801. }
  802. break;
  803. case MVS:
  804. if(node->depth == 0)
  805. cdpath = s_clone(remrootpath);
  806. else{
  807. cdpath = s_new();
  808. mvspath(node, cdpath);
  809. }
  810. break;
  811. default:
  812. if(node->depth == 0)
  813. cdpath = s_clone(remrootpath);
  814. else{
  815. cdpath = s_new();
  816. unixpath(node, cdpath);
  817. }
  818. break;
  819. }
  820. uncachedir(remdir, 0);
  821. /*
  822. * connect, if we need a password (Incomplete)
  823. * act like it worked (best we can do).
  824. */
  825. sendrequest("CWD", s_to_c(cdpath));
  826. s_free(cdpath);
  827. switch(getreply(&ctlin, msg, sizeof(msg), 0)){
  828. case Success:
  829. case Incomplete:
  830. remdir = node;
  831. return 0;
  832. default:
  833. return seterr(nosuchfile);
  834. }
  835. }
  836. /*
  837. * read a remote file
  838. */
  839. int
  840. readfile1(Node *node)
  841. {
  842. Biobuf *bp;
  843. char buf[4*1024];
  844. long off;
  845. int n;
  846. int tries;
  847. if(changedir(node->parent) < 0)
  848. return -1;
  849. for(tries = 0; tries < 4; tries++){
  850. switch(data(OREAD, &bp, "RETR", s_to_c(node->remname))){
  851. case Extra:
  852. break;
  853. case TempFail:
  854. continue;
  855. default:
  856. return seterr(nosuchfile);
  857. }
  858. off = 0;
  859. while((n = read(Bfildes(bp), buf, sizeof buf)) > 0){
  860. if(filewrite(node, buf, off, n) != n){
  861. off = -1;
  862. break;
  863. }
  864. off += n;
  865. }
  866. if(off < 0)
  867. return -1;
  868. /* make sure a file gets created even for a zero length file */
  869. if(off == 0)
  870. filewrite(node, buf, 0, 0);
  871. close(Bfildes(bp));
  872. switch(getreply(&ctlin, msg, sizeof(msg), 0)){
  873. case Success:
  874. return off;
  875. case TempFail:
  876. continue;
  877. default:
  878. return seterr(nosuchfile);
  879. }
  880. }
  881. return seterr(nosuchfile);
  882. }
  883. int
  884. readfile(Node *node)
  885. {
  886. int rv, inimage;
  887. switch(os){
  888. case MVS:
  889. case Plan9:
  890. case Tops:
  891. case TSO:
  892. inimage = 0;
  893. break;
  894. default:
  895. inimage = 1;
  896. image();
  897. break;
  898. }
  899. rv = readfile1(node);
  900. if(inimage)
  901. ascii();
  902. return rv;
  903. }
  904. /*
  905. * write back a file
  906. */
  907. int
  908. createfile1(Node *node)
  909. {
  910. Biobuf *bp;
  911. char buf[4*1024];
  912. long off;
  913. int n;
  914. if(changedir(node->parent) < 0)
  915. return -1;
  916. if(data(OWRITE, &bp, "STOR", s_to_c(node->remname)) != Extra)
  917. return -1;
  918. for(off = 0; ; off += n){
  919. n = fileread(node, buf, off, sizeof(buf));
  920. if(n <= 0)
  921. break;
  922. write(Bfildes(bp), buf, n);
  923. }
  924. close(Bfildes(bp));
  925. if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)
  926. return -1;
  927. return off;
  928. }
  929. int
  930. createfile(Node *node)
  931. {
  932. int rv;
  933. switch(os){
  934. case Plan9:
  935. case Tops:
  936. break;
  937. default:
  938. image();
  939. break;
  940. }
  941. rv = createfile1(node);
  942. switch(os){
  943. case Plan9:
  944. case Tops:
  945. break;
  946. default:
  947. ascii();
  948. break;
  949. }
  950. return rv;
  951. }
  952. /*
  953. * remove a remote file
  954. */
  955. int
  956. removefile(Node *node)
  957. {
  958. if(changedir(node->parent) < 0)
  959. return -1;
  960. sendrequest("DELE", s_to_c(node->remname));
  961. if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)
  962. return -1;
  963. return 0;
  964. }
  965. /*
  966. * remove a remote directory
  967. */
  968. int
  969. removedir(Node *node)
  970. {
  971. if(changedir(node->parent) < 0)
  972. return -1;
  973. sendrequest("RMD", s_to_c(node->remname));
  974. if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)
  975. return -1;
  976. return 0;
  977. }
  978. /*
  979. * tell remote that we're exiting and then do it
  980. */
  981. void
  982. quit(void)
  983. {
  984. sendrequest("QUIT", nil);
  985. getreply(&ctlin, msg, sizeof(msg), 0);
  986. exits(0);
  987. }
  988. /*
  989. * send a request
  990. */
  991. static void
  992. sendrequest(char *a, char *b)
  993. {
  994. char buf[2*1024];
  995. int n;
  996. n = strlen(a)+2+1;
  997. if(b != nil)
  998. n += strlen(b)+1;
  999. if(n >= sizeof(buf))
  1000. fatal("proto request too long");
  1001. strcpy(buf, a);
  1002. if(b != nil){
  1003. strcat(buf, " ");
  1004. strcat(buf, b);
  1005. }
  1006. strcat(buf, "\r\n");
  1007. n = strlen(buf);
  1008. if(write(ctlfd, buf, n) != n)
  1009. fatal("remote side hung up");
  1010. if(debug)
  1011. write(2, buf, n);
  1012. lastsend = time(0);
  1013. }
  1014. /*
  1015. * replies codes are in the range [100, 999] and may contain multiple lines of
  1016. * continuation.
  1017. */
  1018. static int
  1019. getreply(Biobuf *bp, char *msg, int len, int printreply)
  1020. {
  1021. char *line;
  1022. char *p;
  1023. int rv;
  1024. int i, n;
  1025. while(line = Brdline(bp, '\n')){
  1026. /* add line to message buffer, strip off \r */
  1027. n = Blinelen(bp);
  1028. if(n > 1 && line[n-2] == '\r'){
  1029. n--;
  1030. line[n-1] = '\n';
  1031. }
  1032. if(printreply && !quiet)
  1033. write(1, line, n);
  1034. else if(debug)
  1035. write(2, line, n);
  1036. if(n > len - 1)
  1037. i = len - 1;
  1038. else
  1039. i = n;
  1040. if(i > 0){
  1041. memmove(msg, line, i);
  1042. msg += i;
  1043. len -= i;
  1044. *msg = 0;
  1045. }
  1046. /* stop if not a continuation */
  1047. rv = strtol(line, &p, 10);
  1048. if(rv >= 100 && rv < 600 && p==line+3 && *p != '-')
  1049. return rv/100;
  1050. /* tell user about continuations */
  1051. if(!debug && !quiet && !printreply)
  1052. write(2, line, n);
  1053. }
  1054. fatal("remote side closed connection");
  1055. return 0;
  1056. }
  1057. /*
  1058. * Announce on a local port and tell its address to the the remote side
  1059. */
  1060. static int
  1061. port(void)
  1062. {
  1063. char buf[256];
  1064. int n, fd;
  1065. char *ptr;
  1066. uchar ipaddr[IPaddrlen];
  1067. int port;
  1068. /* get a channel to listen on, let kernel pick the port number */
  1069. sprint(buf, "%s!*!0", net);
  1070. listenfd = announce(buf, netdir);
  1071. if(listenfd < 0)
  1072. return seterr("can't announce");
  1073. /* get the local address and port number */
  1074. sprint(buf, "%s/local", netdir);
  1075. fd = open(buf, OREAD);
  1076. if(fd < 0)
  1077. return seterr("opening %s: %r", buf);
  1078. n = read(fd, buf, sizeof(buf)-1);
  1079. close(fd);
  1080. if(n <= 0)
  1081. return seterr("opening %s/local: %r", netdir);
  1082. buf[n] = 0;
  1083. ptr = strchr(buf, ' ');
  1084. if(ptr)
  1085. *ptr = 0;
  1086. ptr = strchr(buf, '!')+1;
  1087. port = atoi(ptr);
  1088. memset(ipaddr, 0, IPaddrlen);
  1089. if (*net){
  1090. strcpy(buf, net);
  1091. ptr = strchr(buf +1, '/');
  1092. if (ptr)
  1093. *ptr = 0;
  1094. myipaddr(ipaddr, buf);
  1095. }
  1096. /* tell remote side */
  1097. sprint(buf, "PORT %d,%d,%d,%d,%d,%d", ipaddr[IPv4off+0], ipaddr[IPv4off+1],
  1098. ipaddr[IPv4off+2], ipaddr[IPv4off+3], port>>8, port&0xff);
  1099. sendrequest(buf, nil);
  1100. if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)
  1101. return seterr(msg);
  1102. return 0;
  1103. }
  1104. /*
  1105. * have server call back for a data connection
  1106. */
  1107. static int
  1108. active(int mode, Biobuf **bpp, char *cmda, char *cmdb)
  1109. {
  1110. int cfd, dfd, rv;
  1111. char newdir[Maxpath];
  1112. char datafile[Maxpath + 6];
  1113. if(port() < 0)
  1114. return TempFail;
  1115. sendrequest(cmda, cmdb);
  1116. rv = getreply(&ctlin, msg, sizeof(msg), 0);
  1117. if(rv != Extra){
  1118. close(listenfd);
  1119. return rv;
  1120. }
  1121. /* wait for a new call */
  1122. cfd = listen(netdir, newdir);
  1123. if(cfd < 0)
  1124. fatal("waiting for data connection");
  1125. close(listenfd);
  1126. /* open it's data connection and close the control connection */
  1127. sprint(datafile, "%s/data", newdir);
  1128. dfd = open(datafile, ORDWR);
  1129. close(cfd);
  1130. if(dfd < 0)
  1131. fatal("opening data connection");
  1132. Binit(&dbuf, dfd, mode);
  1133. *bpp = &dbuf;
  1134. return Extra;
  1135. }
  1136. /*
  1137. * call out for a data connection
  1138. */
  1139. static int
  1140. passive(int mode, Biobuf **bpp, char *cmda, char *cmdb)
  1141. {
  1142. char msg[1024];
  1143. char ds[1024];
  1144. char *f[6];
  1145. char *p;
  1146. int x, fd;
  1147. if(nopassive)
  1148. return Impossible;
  1149. sendrequest("PASV", nil);
  1150. if(getreply(&ctlin, msg, sizeof(msg), 0) != Success){
  1151. nopassive = 1;
  1152. return Impossible;
  1153. }
  1154. /* get address and port number from reply, this is AI */
  1155. p = strchr(msg, '(');
  1156. if(p == 0){
  1157. for(p = msg+3; *p; p++)
  1158. if(isdigit(*p))
  1159. break;
  1160. } else
  1161. p++;
  1162. if(getfields(p, f, 6, 0, ",") < 6){
  1163. if(debug)
  1164. fprint(2, "passive mode protocol botch: %s\n", msg);
  1165. werrstr("ftp protocol botch");
  1166. nopassive = 1;
  1167. return Impossible;
  1168. }
  1169. snprint(ds, sizeof(ds), "%s!%s.%s.%s.%s!%d", net,
  1170. f[0], f[1], f[2], f[3],
  1171. ((atoi(f[4])&0xff)<<8) + (atoi(f[5])&0xff));
  1172. /* open data connection */
  1173. fd = dial(ds, 0, 0, 0);
  1174. if(fd < 0){
  1175. if(debug)
  1176. fprint(2, "passive mode connect to %s failed: %r\n", ds);
  1177. nopassive = 1;
  1178. return TempFail;
  1179. }
  1180. /* tell remote to send a file */
  1181. sendrequest(cmda, cmdb);
  1182. x = getreply(&ctlin, msg, sizeof(msg), 0);
  1183. if(x != Extra){
  1184. close(fd);
  1185. if(debug)
  1186. fprint(2, "passive mode retrieve failed: %s\n", msg);
  1187. werrstr(msg);
  1188. return x;
  1189. }
  1190. Binit(&dbuf, fd, mode);
  1191. *bpp = &dbuf;
  1192. return Extra;
  1193. }
  1194. static int
  1195. data(int mode, Biobuf **bpp, char* cmda, char *cmdb)
  1196. {
  1197. int x;
  1198. x = passive(mode, bpp, cmda, cmdb);
  1199. if(x != Impossible)
  1200. return x;
  1201. return active(mode, bpp, cmda, cmdb);
  1202. }
  1203. /*
  1204. * used for keep alives
  1205. */
  1206. void
  1207. nop(void)
  1208. {
  1209. if(lastsend - time(0) < 15)
  1210. return;
  1211. sendrequest("PWD", nil);
  1212. getreply(&ctlin, msg, sizeof(msg), 0);
  1213. }
  1214. /*
  1215. * turn a vms spec into a path
  1216. */
  1217. static Node*
  1218. vmsextendpath(Node *np, char *name)
  1219. {
  1220. np = extendpath(np, s_copy(name));
  1221. if(!ISVALID(np)){
  1222. np->d->qid.type = QTDIR;
  1223. np->d->atime = time(0);
  1224. np->d->mtime = np->d->atime;
  1225. strcpy(np->d->uid, "who");
  1226. strcpy(np->d->gid, "cares");
  1227. np->d->mode = DMDIR|0777;
  1228. np->d->length = 0;
  1229. if(changedir(np) >= 0)
  1230. VALID(np);
  1231. }
  1232. return np;
  1233. }
  1234. static Node*
  1235. vmsdir(char *name)
  1236. {
  1237. char *cp;
  1238. Node *np;
  1239. char *oname;
  1240. np = remroot;
  1241. cp = strchr(name, '[');
  1242. if(cp)
  1243. strcpy(cp, cp+1);
  1244. cp = strchr(name, ']');
  1245. if(cp)
  1246. *cp = 0;
  1247. oname = name = strdup(name);
  1248. if(name == 0)
  1249. return 0;
  1250. while(cp = strchr(name, '.')){
  1251. *cp = 0;
  1252. np = vmsextendpath(np, name);
  1253. name = cp+1;
  1254. }
  1255. np = vmsextendpath(np, name);
  1256. /*
  1257. * walk back to first accessible directory
  1258. */
  1259. for(; np->parent != np; np = np->parent)
  1260. if(ISVALID(np)){
  1261. CACHED(np->parent);
  1262. break;
  1263. }
  1264. free(oname);
  1265. return np;
  1266. }
  1267. /*
  1268. * walk up the tree building a VMS style path
  1269. */
  1270. static void
  1271. vmspath(Node *node, String *path)
  1272. {
  1273. char *p;
  1274. int n;
  1275. if(node->depth == 1){
  1276. p = strchr(s_to_c(node->remname), ':');
  1277. if(p){
  1278. n = p - s_to_c(node->remname) + 1;
  1279. s_nappend(path, s_to_c(node->remname), n);
  1280. s_append(path, "[");
  1281. s_append(path, p+1);
  1282. } else {
  1283. s_append(path, "[");
  1284. s_append(path, s_to_c(node->remname));
  1285. }
  1286. s_append(path, "]");
  1287. return;
  1288. }
  1289. vmspath(node->parent, path);
  1290. s_append(path, ".");
  1291. s_append(path, s_to_c(node->remname));
  1292. }
  1293. /*
  1294. * walk up the tree building a Unix style path
  1295. */
  1296. static void
  1297. unixpath(Node *node, String *path)
  1298. {
  1299. if(node == node->parent){
  1300. s_append(path, s_to_c(remrootpath));
  1301. return;
  1302. }
  1303. unixpath(node->parent, path);
  1304. if(s_len(path) > 0 && strcmp(s_to_c(path), "/") != 0)
  1305. s_append(path, "/");
  1306. s_append(path, s_to_c(node->remname));
  1307. }
  1308. /*
  1309. * walk up the tree building a MVS style path
  1310. */
  1311. static void
  1312. mvspath(Node *node, String *path)
  1313. {
  1314. if(node == node->parent){
  1315. s_append(path, s_to_c(remrootpath));
  1316. return;
  1317. }
  1318. mvspath(node->parent, path);
  1319. if(s_len(path) > 0)
  1320. s_append(path, ".");
  1321. s_append(path, s_to_c(node->remname));
  1322. }
  1323. static int
  1324. getpassword(char *buf, char *e)
  1325. {
  1326. char *p;
  1327. int c;
  1328. int consctl, rv = 0;
  1329. consctl = open("/dev/consctl", OWRITE);
  1330. if(consctl >= 0)
  1331. write(consctl, "rawon", 5);
  1332. print("Password: ");
  1333. e--;
  1334. for(p = buf; p <= e; p++){
  1335. c = Bgetc(&stdin);
  1336. if(c < 0){
  1337. rv = -1;
  1338. goto out;
  1339. }
  1340. if(c == '\n' || c == '\r')
  1341. break;
  1342. *p = c;
  1343. }
  1344. *p = 0;
  1345. print("\n");
  1346. out:
  1347. if(consctl >= 0)
  1348. close(consctl);
  1349. return rv;
  1350. }
  1351. /*
  1352. * convert from latin1 to utf
  1353. */
  1354. static char*
  1355. fromlatin1(char *from)
  1356. {
  1357. char *p, *to;
  1358. Rune r;
  1359. if(os == Plan9)
  1360. return nil;
  1361. /* don't convert if we don't have to */
  1362. for(p = from; *p; p++)
  1363. if(*p & 0x80)
  1364. break;
  1365. if(*p == 0)
  1366. return nil;
  1367. to = malloc(3*strlen(from)+2);
  1368. if(to == nil)
  1369. return nil;
  1370. for(p = to; *from; from++){
  1371. r = (*from) & 0xff;
  1372. p += runetochar(p, &r);
  1373. }
  1374. *p = 0;
  1375. return to;
  1376. }
  1377. Dir*
  1378. reallocdir(Dir *d, int dofree)
  1379. {
  1380. Dir *dp;
  1381. char *p;
  1382. int nn, ng, nu, nm;
  1383. char *utf;
  1384. if(d->name == nil)
  1385. d->name = "?name?";
  1386. if(d->uid == nil)
  1387. d->uid = "?uid?";
  1388. if(d->gid == nil)
  1389. d->gid = d->uid;
  1390. if(d->muid == nil)
  1391. d->muid = d->uid;
  1392. utf = fromlatin1(d->name);
  1393. if(utf != nil)
  1394. d->name = utf;
  1395. nn = strlen(d->name)+1;
  1396. nu = strlen(d->uid)+1;
  1397. ng = strlen(d->gid)+1;
  1398. nm = strlen(d->muid)+1;
  1399. dp = malloc(sizeof(Dir)+nn+nu+ng+nm);
  1400. if(dp == nil){
  1401. if(dofree)
  1402. free(d);
  1403. if(utf != nil)
  1404. free(utf);
  1405. return nil;
  1406. }
  1407. *dp = *d;
  1408. p = (char*)&dp[1];
  1409. strcpy(p, d->name);
  1410. dp->name = p;
  1411. p += nn;
  1412. strcpy(p, d->uid);
  1413. dp->uid = p;
  1414. p += nu;
  1415. strcpy(p, d->gid);
  1416. dp->gid = p;
  1417. p += ng;
  1418. strcpy(p, d->muid);
  1419. dp->muid = p;
  1420. if(dofree)
  1421. free(d);
  1422. if(utf != nil)
  1423. free(utf);
  1424. return dp;
  1425. }
  1426. Dir*
  1427. dir_change_name(Dir *d, char *name)
  1428. {
  1429. if(d->name && strlen(d->name) >= strlen(name)){
  1430. strcpy(d->name, name);
  1431. return d;
  1432. }
  1433. d->name = name;
  1434. return reallocdir(d, 1);
  1435. }
  1436. Dir*
  1437. dir_change_uid(Dir *d, char *name)
  1438. {
  1439. if(d->uid && strlen(d->uid) >= strlen(name)){
  1440. strcpy(d->name, name);
  1441. return d;
  1442. }
  1443. d->uid = name;
  1444. return reallocdir(d, 1);
  1445. }
  1446. Dir*
  1447. dir_change_gid(Dir *d, char *name)
  1448. {
  1449. if(d->gid && strlen(d->gid) >= strlen(name)){
  1450. strcpy(d->name, name);
  1451. return d;
  1452. }
  1453. d->gid = name;
  1454. return reallocdir(d, 1);
  1455. }
  1456. Dir*
  1457. dir_change_muid(Dir *d, char *name)
  1458. {
  1459. if(d->muid && strlen(d->muid) >= strlen(name)){
  1460. strcpy(d->name, name);
  1461. return d;
  1462. }
  1463. d->muid = name;
  1464. return reallocdir(d, 1);
  1465. }
  1466. static int
  1467. nw_mode(char dirlet, char *s) /* NetWare file mode mapping */
  1468. {
  1469. int mode = 0777;
  1470. if(dirlet == 'd')
  1471. mode |= DMDIR;
  1472. if (strlen(s) >= 10 && s[0] != '[' || s[9] != ']')
  1473. return(mode);
  1474. if (s[1] == '-') /* can't read file */
  1475. mode &= ~0444;
  1476. if (dirlet == 'd' && s[6] == '-') /* cannot scan dir */
  1477. mode &= ~0444;
  1478. if (s[2] == '-') /* can't write file */
  1479. mode &= ~0222;
  1480. if (dirlet == 'd' && s[7] == '-' && s[3] == '-') /* cannot create in, or modify dir */
  1481. mode &= ~0222;
  1482. return(mode);
  1483. }