shared_ftp_fish.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891
  1. /*
  2. * Shared code between the fish.c and the ftp.c file systems
  3. *
  4. * Actually, this code is not being used by fish.c any more :-).
  5. *
  6. * Namespace pollution: X_hint_reread, X_flushdir.
  7. */
  8. static int store_file (struct direntry *fe);
  9. static int retrieve_file (struct direntry *fe);
  10. static int remove_temp_file (char *file_name);
  11. static struct dir *retrieve_dir (struct connection *bucket,
  12. char *remote_path,
  13. int resolve_symlinks);
  14. static void my_forget (char *path);
  15. static int linear_start (struct direntry *fe, int from);
  16. static int linear_read (struct direntry *fe, void *buf, int len);
  17. static void linear_close (struct direntry *fe);
  18. static int
  19. select_on_two (int fd1, int fd2)
  20. {
  21. fd_set set;
  22. struct timeval timeout;
  23. int v;
  24. int maxfd = (fd1 > fd2 ? fd1 : fd2) + 1;
  25. timeout.tv_sec = 1;
  26. timeout.tv_usec = 0;
  27. FD_ZERO(&set);
  28. FD_SET(fd1, &set);
  29. FD_SET(fd2, &set);
  30. v = select (maxfd, &set, 0, 0, &timeout);
  31. if (v <= 0)
  32. return v;
  33. if (FD_ISSET (fd1, &set))
  34. return 1;
  35. if (FD_ISSET (fd2, &set))
  36. return 2;
  37. return -1;
  38. }
  39. static int
  40. get_line (int sock, char *buf, int buf_len, char term)
  41. {
  42. int i, status;
  43. char c;
  44. for (i = 0; i < buf_len; i++, buf++) {
  45. if (read(sock, buf, sizeof(char)) <= 0)
  46. return 0;
  47. if (logfile){
  48. fwrite (buf, 1, 1, logfile);
  49. fflush (logfile);
  50. }
  51. if (*buf == term) {
  52. *buf = 0;
  53. return 1;
  54. }
  55. }
  56. *buf = 0;
  57. while ((status = read(sock, &c, sizeof(c))) > 0){
  58. if (logfile){
  59. fwrite (&c, 1, 1, logfile);
  60. fflush (logfile);
  61. }
  62. if (c == '\n')
  63. return 1;
  64. }
  65. return 0;
  66. }
  67. static void
  68. direntry_destructor (void *data)
  69. {
  70. struct direntry *fe = data;
  71. fe->count--;
  72. if (fe->count > 0)
  73. return;
  74. free(fe->name);
  75. if (fe->linkname)
  76. free(fe->linkname);
  77. if (fe->local_filename) {
  78. if (fe->local_is_temp) {
  79. if (!fe->local_stat.st_mtime)
  80. unlink(fe->local_filename);
  81. else {
  82. struct stat sb;
  83. if (stat (fe->local_filename, &sb) >=0 &&
  84. fe->local_stat.st_mtime == sb.st_mtime)
  85. unlink (fe->local_filename); /* Delete only if it hasn't changed */
  86. }
  87. }
  88. free(fe->local_filename);
  89. fe->local_filename = NULL;
  90. }
  91. if (fe->remote_filename)
  92. free(fe->remote_filename);
  93. if (fe->l_stat)
  94. free(fe->l_stat);
  95. free(fe);
  96. }
  97. static void
  98. dir_destructor(void *data)
  99. {
  100. struct dir *fd = data;
  101. fd->count--;
  102. if (fd->count > 0)
  103. return;
  104. free(fd->remote_path);
  105. linklist_destroy(fd->file_list, direntry_destructor);
  106. free(fd);
  107. }
  108. static int
  109. get_line_interruptible (char *buffer, int size, int fd)
  110. {
  111. int n;
  112. int i = 0;
  113. for (i = 0; i < size-1; i++) {
  114. n = read (fd, buffer+i, 1);
  115. if (n == -1 && errno == EINTR){
  116. buffer [i] = 0;
  117. return EINTR;
  118. }
  119. if (n == 0){
  120. buffer [i] = 0;
  121. return 0;
  122. }
  123. if (buffer [i] == '\n'){
  124. buffer [i] = 0;
  125. return 1;
  126. }
  127. }
  128. buffer [size-1] = 0;
  129. return 0;
  130. }
  131. static void
  132. free_bucket (void *data)
  133. {
  134. struct connection *bucket = data;
  135. free(qhost(bucket));
  136. free(quser(bucket));
  137. if (qcdir(bucket))
  138. free(qcdir(bucket));
  139. if (qhome(bucket))
  140. free(qhome(bucket));
  141. if (qupdir(bucket))
  142. free(qupdir(bucket));
  143. if (bucket->password)
  144. wipe_password (bucket->password);
  145. linklist_destroy(qdcache(bucket), dir_destructor);
  146. free(bucket);
  147. }
  148. static void
  149. connection_destructor(void *data)
  150. {
  151. connection_close (data);
  152. free_bucket (data);
  153. }
  154. static void
  155. flush_all_directory(struct connection *bucket)
  156. {
  157. linklist_delete_all(qdcache(bucket), dir_destructor);
  158. }
  159. static void X_fill_names (vfs *me, void (*func)(char *))
  160. {
  161. struct linklist *lptr;
  162. char *path_name;
  163. struct connection *bucket;
  164. if (!connections_list)
  165. return;
  166. lptr = connections_list;
  167. do {
  168. if ((bucket = lptr->data) != 0){
  169. path_name = copy_strings ( X_myname, quser (bucket),
  170. "@", qhost (bucket),
  171. qcdir(bucket), 0);
  172. (*func)(path_name);
  173. free (path_name);
  174. }
  175. lptr = lptr->next;
  176. } while (lptr != connections_list);
  177. }
  178. /* get_path:
  179. * makes BUCKET point to the connection bucket descriptor for PATH
  180. * returns a malloced string with the pathname relative to BUCKET.
  181. *
  182. * path must _not_ contain initial /bla/#ftp:
  183. */
  184. static char*
  185. s_get_path (struct connection **bucket, char *path, char *name)
  186. {
  187. char *user, *host, *remote_path, *pass;
  188. int port;
  189. #ifndef BROKEN_PATHS
  190. if (strncmp (path, name, strlen (name)))
  191. return NULL; /* Normal: consider cd /bla/#ftp */
  192. #else
  193. if (!(path = strstr (path, name)))
  194. return NULL;
  195. #endif
  196. path += strlen (name);
  197. if (!(remote_path = my_get_host_and_username (path, &host, &user, &port, &pass)))
  198. my_errno = ENOENT;
  199. else {
  200. if ((*bucket = open_link (host, user, port, pass)) == NULL) {
  201. free (remote_path);
  202. remote_path = NULL;
  203. }
  204. }
  205. free (host);
  206. free (user);
  207. if (pass)
  208. wipe_password (pass);
  209. if (!remote_path)
  210. return NULL;
  211. /* NOTE: Usage of tildes is deprecated, consider:
  212. * cd /#ftp:pavel@hobit
  213. * cd ~
  214. * And now: what do I want to do? Do I want to go to /home/pavel or to
  215. * /#ftp:hobit/home/pavel? I think first has better sense...
  216. */
  217. {
  218. int f = !strcmp( remote_path, "/~" );
  219. if (f || !strncmp( remote_path, "/~/", 3 )) {
  220. char *s;
  221. s = concat_dir_and_file( qhome (*bucket), remote_path +3-f );
  222. free (remote_path);
  223. remote_path = s;
  224. }
  225. }
  226. return remote_path;
  227. }
  228. void
  229. X_flushdir (void)
  230. {
  231. force_expiration = 1;
  232. }
  233. static int
  234. s_setctl (vfs *me, char *path, int ctlop, char *arg)
  235. {
  236. switch (ctlop) {
  237. case MCCTL_REMOVELOCALCOPY:
  238. return remove_temp_file (path);
  239. return 0;
  240. case MCCTL_FORGET_ABOUT:
  241. my_forget(path);
  242. return 0;
  243. }
  244. return 0;
  245. }
  246. static struct direntry *
  247. _get_file_entry(struct connection *bucket, char *file_name,
  248. int op, int flags)
  249. {
  250. char *p, q;
  251. struct direntry *ent;
  252. struct linklist *file_list, *lptr;
  253. struct dir *dcache;
  254. struct stat sb;
  255. p = strrchr(file_name, '/');
  256. q = *p;
  257. *p = '\0';
  258. dcache = retrieve_dir(bucket, *file_name ? file_name : "/", op & DO_RESOLVE_SYMLINK);
  259. if (dcache == NULL)
  260. return NULL;
  261. file_list = dcache->file_list;
  262. *p++ = q;
  263. if (!*p)
  264. p = ".";
  265. for (lptr = file_list->next; lptr != file_list; lptr = lptr->next) {
  266. ent = lptr->data;
  267. if (strcmp(p, ent->name) == 0) {
  268. if (S_ISLNK(ent->s.st_mode) && (op & DO_RESOLVE_SYMLINK)) {
  269. if (ent->l_stat == NULL) ERRNOR (ENOENT, NULL);
  270. if (S_ISLNK(ent->l_stat->st_mode)) ERRNOR (ELOOP, NULL);
  271. }
  272. if (ent && (op & DO_OPEN)) {
  273. mode_t fmode;
  274. fmode = S_ISLNK(ent->s.st_mode)
  275. ? ent->l_stat->st_mode
  276. : ent->s.st_mode;
  277. if (S_ISDIR(fmode)) ERRNOR (EISDIR, NULL);
  278. if (!S_ISREG(fmode)) ERRNOR (EPERM, NULL);
  279. if ((flags & O_EXCL) && (flags & O_CREAT)) ERRNOR (EEXIST, NULL);
  280. if (ent->remote_filename == NULL)
  281. if (!(ent->remote_filename = strdup(file_name))) ERRNOR (ENOMEM, NULL);
  282. if (ent->local_filename == NULL ||
  283. !ent->local_stat.st_mtime ||
  284. stat (ent->local_filename, &sb) < 0 ||
  285. sb.st_mtime != ent->local_stat.st_mtime) {
  286. int handle;
  287. if (ent->local_filename){
  288. free (ent->local_filename);
  289. ent->local_filename = NULL;
  290. }
  291. if (flags & O_TRUNC) {
  292. ent->local_filename = tempnam (NULL, X "fs");
  293. if (ent->local_filename == NULL) ERRNOR (ENOMEM, NULL);
  294. handle = open(ent->local_filename, O_CREAT | O_TRUNC | O_RDWR | O_EXCL, 0600);
  295. if (handle < 0) ERRNOR (EIO, NULL);
  296. close(handle);
  297. if (stat (ent->local_filename, &ent->local_stat) < 0)
  298. ent->local_stat.st_mtime = 0;
  299. }
  300. else {
  301. if (IS_LINEAR(flags)) {
  302. ent->local_is_temp = 0;
  303. ent->local_filename = NULL;
  304. ent->linear_state = LS_LINEAR_CLOSED;
  305. return ent;
  306. }
  307. if (!retrieve_file(ent))
  308. return NULL;
  309. }
  310. }
  311. else if (flags & O_TRUNC) {
  312. truncate(ent->local_filename, 0);
  313. }
  314. }
  315. return ent;
  316. }
  317. }
  318. if ((op & DO_OPEN) && (flags & O_CREAT)) {
  319. int handle;
  320. ent = xmalloc(sizeof(struct direntry), "struct direntry");
  321. ent->freshly_created = 0;
  322. if (ent == NULL) ERRNOR (ENOMEM, NULL);
  323. ent->count = 1;
  324. ent->linkname = NULL;
  325. ent->l_stat = NULL;
  326. ent->bucket = bucket;
  327. ent->name = strdup(p);
  328. ent->remote_filename = strdup(file_name);
  329. ent->local_filename = tempnam (NULL, X "fs");
  330. if (!ent->name && !ent->remote_filename && !ent->local_filename) {
  331. direntry_destructor(ent);
  332. ERRNOR (ENOMEM, NULL);
  333. }
  334. handle = creat(ent->local_filename, 0700);
  335. if (handle == -1) {
  336. my_errno = EIO;
  337. goto error;
  338. }
  339. fstat(handle, &ent->s);
  340. close(handle);
  341. #if 0
  342. /* This is very wrong - like this a zero length file will be always created
  343. and usually preclude uploading anything more desirable */
  344. #if defined(UPLOAD_ZERO_LENGTH_FILE)
  345. if (!store_file(ent)) goto error;
  346. #endif
  347. #endif
  348. if (!linklist_insert(file_list, ent)) {
  349. my_errno = ENOMEM;
  350. goto error;
  351. }
  352. ent->freshly_created = 1;
  353. return ent;
  354. }
  355. else ERRNOR (ENOENT, NULL);
  356. error:
  357. direntry_destructor(ent);
  358. return NULL;
  359. }
  360. /* this just free's the local temp file. I don't know if the
  361. remote file can be used after this without crashing - paul
  362. psheer@obsidian.co.za psheer@icon.co.za */
  363. static int
  364. remove_temp_file (char *file_name)
  365. {
  366. char *p, q;
  367. struct connection *bucket;
  368. struct direntry *ent;
  369. struct linklist *file_list, *lptr;
  370. struct dir *dcache;
  371. if (!(file_name = get_path (&bucket, file_name)))
  372. return -1;
  373. p = strrchr (file_name, '/');
  374. q = *p;
  375. *p = '\0';
  376. dcache = retrieve_dir (bucket, *file_name ? file_name : "/", 0);
  377. if (dcache == NULL)
  378. return -1;
  379. file_list = dcache->file_list;
  380. *p++ = q;
  381. if (!*p)
  382. p = ".";
  383. for (lptr = file_list->next; lptr != file_list; lptr = lptr->next) {
  384. ent = lptr->data;
  385. if (strcmp (p, ent->name) == 0) {
  386. if (ent->local_filename) {
  387. unlink (ent->local_filename);
  388. free (ent->local_filename);
  389. ent->local_filename = NULL;
  390. return 0;
  391. }
  392. }
  393. }
  394. return -1;
  395. }
  396. static struct direntry *
  397. get_file_entry(char *path, int op, int flags)
  398. {
  399. struct connection *bucket;
  400. struct direntry *fe;
  401. char *remote_path;
  402. if (!(remote_path = get_path (&bucket, path)))
  403. return NULL;
  404. fe = _get_file_entry(bucket, remote_path, op,
  405. flags);
  406. free(remote_path);
  407. #if 0
  408. if (op & DO_FREE_RESOURCE)
  409. vfs_add_noncurrent_stamps (&vfs_X_ops, (vfsid) bucket, NULL);
  410. #endif
  411. return fe;
  412. }
  413. #define OPT_FLUSH 1
  414. #define OPT_IGNORE_ERROR 2
  415. static int normal_flush = 1;
  416. void X_hint_reread(int reread)
  417. {
  418. if (reread)
  419. normal_flush++;
  420. else
  421. normal_flush--;
  422. }
  423. /* The callbacks */
  424. struct filp {
  425. unsigned int has_changed:1;
  426. struct direntry *fe;
  427. int local_handle;
  428. };
  429. static void *s_open (vfs *me, char *file, int flags, int mode)
  430. {
  431. struct filp *fp;
  432. struct direntry *fe;
  433. fp = xmalloc(sizeof(struct filp), "struct filp");
  434. if (fp == NULL) ERRNOR (ENOMEM, NULL);
  435. fe = get_file_entry(file, DO_OPEN | DO_RESOLVE_SYMLINK, flags);
  436. if (!fe) {
  437. free(fp);
  438. return NULL;
  439. }
  440. fe->linear_state = IS_LINEAR(flags);
  441. if (!fe->linear_state) {
  442. fp->local_handle = open(fe->local_filename, flags, mode);
  443. if (fp->local_handle < 0) {
  444. free(fp);
  445. ERRNOR (errno, NULL);
  446. }
  447. } else fp->local_handle = -1;
  448. #ifdef UPLOAD_ZERO_LENGTH_FILE
  449. fp->has_changed = fe->freshly_created;
  450. #else
  451. fp->has_changed = 0;
  452. #endif
  453. fp->fe = fe;
  454. qlock(fe->bucket)++;
  455. fe->count++;
  456. return fp;
  457. }
  458. static int s_read (void *data, char *buffer, int count)
  459. {
  460. struct filp *fp;
  461. int n;
  462. fp = data;
  463. if (fp->fe->linear_state == LS_LINEAR_CLOSED) {
  464. print_vfs_message ("Starting linear transfer...");
  465. if (!linear_start (fp->fe, 0))
  466. return -1;
  467. }
  468. if (fp->fe->linear_state == LS_LINEAR_CLOSED)
  469. vfs_die ("linear_start() did not set linear_state!");
  470. if (fp->fe->linear_state == LS_LINEAR_OPEN)
  471. return linear_read (fp->fe, buffer, count);
  472. n = read (fp->local_handle, buffer, count);
  473. if (n < 0)
  474. my_errno = errno;
  475. return n;
  476. }
  477. static int s_write (void *data, char *buf, int nbyte)
  478. {
  479. struct filp *fp = data;
  480. int n;
  481. if (fp->fe->linear_state)
  482. vfs_die ("You may not write to linear file");
  483. n = write (fp->local_handle, buf, nbyte);
  484. if (n < 0)
  485. my_errno = errno;
  486. fp->has_changed = 1;
  487. return n;
  488. }
  489. static int s_close (void *data)
  490. {
  491. struct filp *fp = data;
  492. int result = 0;
  493. if (fp->has_changed) {
  494. if (!store_file(fp->fe))
  495. result = -1;
  496. if (normal_flush)
  497. flush_all_directory(fp->fe->bucket);
  498. }
  499. if (fp->fe->linear_state == LS_LINEAR_OPEN)
  500. linear_close(fp->fe);
  501. if (fp->local_handle >= 0)
  502. close(fp->local_handle);
  503. qlock(fp->fe->bucket)--;
  504. direntry_destructor(fp->fe);
  505. free(fp);
  506. return result;
  507. }
  508. static int s_errno (vfs *me)
  509. {
  510. return my_errno;
  511. }
  512. /* Explanation:
  513. * On some operating systems (Slowaris 2 for example)
  514. * the d_name member is just a char long (nice trick that break everything),
  515. * so we need to set up some space for the filename.
  516. */
  517. struct my_dirent {
  518. struct dirent dent;
  519. #ifdef NEED_EXTRA_DIRENT_BUFFER
  520. char extra_buffer [MC_MAXPATHLEN];
  521. #endif
  522. struct linklist *pos;
  523. struct dir *dcache;
  524. };
  525. /* Possible FIXME: what happens if one directory is opened twice ? */
  526. static void *s_opendir (vfs *me, char *dirname)
  527. {
  528. struct connection *bucket;
  529. char *remote_path;
  530. struct my_dirent *dirp;
  531. if (!(remote_path = get_path (&bucket, dirname)))
  532. return NULL;
  533. dirp = xmalloc(sizeof(struct my_dirent), "struct my_dirent");
  534. if (dirp == NULL) {
  535. my_errno = ENOMEM;
  536. goto error_return;
  537. }
  538. dirp->dcache = retrieve_dir(bucket, remote_path, 1);
  539. if (dirp->dcache == NULL)
  540. goto error_return;
  541. dirp->pos = dirp->dcache->file_list->next;
  542. free(remote_path);
  543. dirp->dcache->count++;
  544. return (void *)dirp;
  545. error_return:
  546. vfs_add_noncurrent_stamps (&vfs_X_ops, (vfsid) bucket, NULL);
  547. free(remote_path);
  548. free(dirp);
  549. return NULL;
  550. }
  551. static void *s_readdir (void *data)
  552. {
  553. struct direntry *fe;
  554. struct my_dirent *dirp = data;
  555. if (dirp->pos == dirp->dcache->file_list)
  556. return NULL;
  557. fe = dirp->pos->data;
  558. strcpy (&(dirp->dent.d_name [0]), fe->name);
  559. #ifndef DIRENT_LENGTH_COMPUTED
  560. dirp->d_namlen = strlen (dirp->d_name);
  561. #endif
  562. dirp->pos = dirp->pos->next;
  563. return (void *) &dirp->dent;
  564. }
  565. static int s_telldir (void *data)
  566. {
  567. struct my_dirent *dirp = data;
  568. struct linklist *pos;
  569. int i = 0;
  570. pos = dirp->dcache->file_list->next;
  571. while( pos!=dirp->dcache->file_list) {
  572. if (pos == dirp->pos)
  573. return i;
  574. pos = pos->next;
  575. i++;
  576. }
  577. return -1;
  578. }
  579. static void s_seekdir (void *data, int pos)
  580. {
  581. struct my_dirent *dirp = data;
  582. int i;
  583. dirp->pos = dirp->dcache->file_list->next;
  584. for (i=0; i<pos; i++)
  585. s_readdir(data);
  586. }
  587. static int s_closedir (void *info)
  588. {
  589. struct my_dirent *dirp = info;
  590. dir_destructor(dirp->dcache);
  591. free(dirp);
  592. return 0;
  593. }
  594. static int s_lstat (vfs *me, char *path, struct stat *buf)
  595. {
  596. struct direntry *fe;
  597. fe = get_file_entry(path, DO_FREE_RESOURCE, 0);
  598. if (fe) {
  599. *buf = fe->s;
  600. return 0;
  601. }
  602. else
  603. return -1;
  604. }
  605. static int s_stat (vfs *me, char *path, struct stat *buf)
  606. {
  607. struct direntry *fe;
  608. fe = get_file_entry(path, DO_RESOLVE_SYMLINK | DO_FREE_RESOURCE, 0);
  609. if (fe) {
  610. if (!S_ISLNK(fe->s.st_mode))
  611. *buf = fe->s;
  612. else
  613. *buf = *fe->l_stat;
  614. return 0;
  615. }
  616. else
  617. return -1;
  618. }
  619. static int s_fstat (void *data, struct stat *buf)
  620. {
  621. struct filp *fp = data;
  622. if (!S_ISLNK(fp->fe->s.st_mode))
  623. *buf = fp->fe->s;
  624. else
  625. *buf = *fp->fe->l_stat;
  626. return 0;
  627. }
  628. static int s_readlink (vfs *me, char *path, char *buf, int size)
  629. {
  630. struct direntry *fe;
  631. fe = get_file_entry(path, DO_FREE_RESOURCE, 0);
  632. if (!fe)
  633. return -1;
  634. if (!S_ISLNK(fe->s.st_mode)) ERRNOR (EINVAL, -1);
  635. if (fe->linkname == NULL) ERRNOR (EACCES, -1);
  636. if (strlen(fe->linkname) >= size) ERRNOR (ERANGE, -1);
  637. strncpy(buf, fe->linkname, size);
  638. return strlen(fe->linkname);
  639. }
  640. static int s_chdir (vfs *me, char *path)
  641. {
  642. char *remote_path;
  643. struct connection *bucket;
  644. if (!(remote_path = get_path(&bucket, path)))
  645. return -1;
  646. if (qcdir(bucket))
  647. free(qcdir(bucket));
  648. qcdir(bucket) = remote_path;
  649. bucket->cwd_defered = 1;
  650. vfs_add_noncurrent_stamps (&vfs_X_ops, (vfsid) bucket, NULL);
  651. return 0;
  652. }
  653. static int s_lseek (void *data, off_t offset, int whence)
  654. {
  655. struct filp *fp = data;
  656. if (fp->fe->linear_state == LS_LINEAR_OPEN)
  657. vfs_die ("You promissed not to seek!");
  658. if (fp->fe->linear_state == LS_LINEAR_CLOSED) {
  659. print_vfs_message ("Preparing reget...");
  660. if (whence != SEEK_SET)
  661. vfs_die ("You may not do such seek on linear file");
  662. if (!linear_start (fp->fe, offset))
  663. return -1;
  664. return offset;
  665. }
  666. return lseek(fp->local_handle, offset, whence);
  667. }
  668. static vfsid s_getid (vfs *me, char *p, struct vfs_stamping **parent)
  669. {
  670. struct connection *bucket;
  671. char *remote_path;
  672. *parent = NULL; /* We are not enclosed in any other fs */
  673. if (!(remote_path = get_path (&bucket, p)))
  674. return (vfsid) -1;
  675. else {
  676. free(remote_path);
  677. return (vfsid) bucket;
  678. }
  679. }
  680. static int s_nothingisopen (vfsid id)
  681. {
  682. return qlock((struct connection *)id) == 0;
  683. }
  684. static void s_free (vfsid id)
  685. {
  686. struct connection *bucket = (struct connection *) id;
  687. connection_destructor(bucket);
  688. linklist_delete(connections_list, bucket);
  689. }
  690. static char *s_getlocalcopy (vfs *me, char *path)
  691. {
  692. struct filp *fp = (struct filp *) s_open (me, path, O_RDONLY, 0);
  693. char *p;
  694. if (fp == NULL)
  695. return NULL;
  696. if (fp->fe->local_filename == NULL) {
  697. s_close ((void *) fp);
  698. return NULL;
  699. }
  700. p = strdup (fp->fe->local_filename);
  701. qlock(fp->fe->bucket)++;
  702. fp->fe->count++;
  703. s_close ((void *) fp);
  704. return p;
  705. }
  706. static void s_ungetlocalcopy (vfs *me, char *path, char *local, int has_changed)
  707. {
  708. struct filp *fp = (struct filp *) s_open (me, path, O_WRONLY, 0);
  709. if (fp == NULL)
  710. return;
  711. if (!strcmp (fp->fe->local_filename, local)) {
  712. fp->has_changed = has_changed;
  713. qlock(fp->fe->bucket)--;
  714. direntry_destructor(fp->fe);
  715. s_close ((void *) fp);
  716. } else {
  717. /* Should not happen */
  718. s_close ((void *) fp);
  719. mc_def_ungetlocalcopy (me, path, local, has_changed);
  720. }
  721. }
  722. static void
  723. X_done(vfs *me)
  724. {
  725. linklist_destroy(connections_list, connection_destructor);
  726. connections_list = NULL;
  727. if (logfile)
  728. fclose (logfile);
  729. logfile = NULL;
  730. }
  731. static int retrieve_file(struct direntry *fe)
  732. {
  733. /* If you want reget, you'll have to open file with O_LINEAR */
  734. int total = 0;
  735. char buffer[8192];
  736. int local_handle, n;
  737. int stat_size = fe->s.st_size;
  738. if (fe->local_filename)
  739. return 1;
  740. if (!(fe->local_filename = tempnam (NULL, X))) ERRNOR (ENOMEM, 0);
  741. fe->local_is_temp = 1;
  742. local_handle = open(fe->local_filename, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600);
  743. if (local_handle == -1) {
  744. my_errno = EIO;
  745. goto error_4;
  746. }
  747. if (!linear_start (fe, 0))
  748. goto error_3;
  749. /* Clear the interrupt status */
  750. enable_interrupt_key ();
  751. while (1) {
  752. if ((n = linear_read(fe, buffer, sizeof(buffer))) < 0)
  753. goto error_1;
  754. if (!n)
  755. break;
  756. total += n;
  757. vfs_print_stats (X, "Getting file", fe->remote_filename, total, stat_size);
  758. while (write(local_handle, buffer, n) < 0) {
  759. if (errno == EINTR) {
  760. if (got_interrupt()) {
  761. my_errno = EINTR;
  762. goto error_2;
  763. }
  764. else
  765. continue;
  766. }
  767. my_errno = errno;
  768. goto error_1;
  769. }
  770. }
  771. linear_close(fe);
  772. disable_interrupt_key();
  773. close(local_handle);
  774. if (stat (fe->local_filename, &fe->local_stat) < 0)
  775. fe->local_stat.st_mtime = 0;
  776. return 1;
  777. error_1:
  778. error_2:
  779. linear_close(fe);
  780. error_3:
  781. disable_interrupt_key();
  782. close(local_handle);
  783. unlink(fe->local_filename);
  784. error_4:
  785. free(fe->local_filename);
  786. fe->local_filename = NULL;
  787. return 0;
  788. }