FileManip.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $TOG: FileManip.c /main/10 1999/12/09 13:06:10 mgreess $ */
  24. /************************************<+>*************************************
  25. ****************************************************************************
  26. *
  27. * FILE: FileManip.c
  28. *
  29. * COMPONENT_NAME: Desktop File Manager (dtfile)
  30. *
  31. * Description: This module does the copy, move and rename commands.
  32. * Included are functions to control command execution,
  33. * move a directory, get the directory portion of a pathname,
  34. * get the file name portion of a pathname, and check if a
  35. * folder is to be moved within itself.
  36. *
  37. * FUNCTIONS: Check
  38. * CheckAccess
  39. * CopyDir
  40. * DName
  41. * FileManip
  42. * FileOperationError
  43. * MoveDir
  44. * defined
  45. *
  46. * (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
  47. * (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
  48. * (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
  49. * (c) Copyright 1993, 1994, 1995 Novell, Inc.
  50. *
  51. ****************************************************************************
  52. ************************************<+>*************************************/
  53. #if defined(SVR4)
  54. # include <sys/fs/ufs_fs.h>
  55. # define ROOTINO UFSROOTINO
  56. #else
  57. # if defined(__linux__) || defined(CSRG_BASED)
  58. # define ROOTINO 2
  59. # endif
  60. # include <sys/param.h>
  61. #endif /* SVR4 */
  62. #include <sys/types.h>
  63. #include <sys/stat.h>
  64. #include <stdio.h>
  65. #include <signal.h>
  66. #include <errno.h>
  67. #include <fcntl.h>
  68. #include <unistd.h>
  69. #include <limits.h>
  70. #if defined(sun) && !defined(SVR4)
  71. #include <ufs/fs.h>
  72. #endif
  73. #include <Xm/Xm.h>
  74. #include <Xm/MwmUtil.h>
  75. #include <Dt/DtP.h> /* required for DtDirPaths type */
  76. #include <Dt/Connect.h>
  77. #include <Dt/DtNlUtils.h>
  78. #include <Dt/SharedProcs.h>
  79. #include "Encaps.h"
  80. #include "SharedProcs.h"
  81. #include "FileMgr.h"
  82. #include "Desktop.h"
  83. #include "Main.h"
  84. #include "Help.h"
  85. #include "SharedMsgs.h"
  86. #ifndef CDE_INSTALLATION_TOP
  87. #define CDE_INSTALLATION_TOP "/usr/dt"
  88. #endif
  89. /* Local Function Definitions */
  90. static char * MOVE_CMD = "/bin/mv";
  91. static char * LINK_CMD = "/bin/ln";
  92. static char * REMOVE_CMD = "/bin/rm";
  93. static char * DTCOPY = CDE_INSTALLATION_TOP "/bin/dtfile_copy";
  94. /************************************************************************
  95. *
  96. * CheckAccess
  97. *
  98. ************************************************************************/
  99. int
  100. CheckAccess(
  101. char *fname,
  102. int what)
  103. {
  104. int access_priv;
  105. uid_t save_ruid;
  106. gid_t save_rgid;
  107. #ifdef BLS
  108. /*--------------------------------------------------------------------
  109. * access code for BLS
  110. *------------------------------------------------------------------*/
  111. setresuid(geteuid(),-1,-1);
  112. return access (fname, what);
  113. #else /* the rest of the OS's */
  114. save_ruid = getuid();
  115. #ifdef _AIX
  116. setreuid(geteuid(),-1);
  117. #else
  118. setuid(geteuid());
  119. #endif /* _AIX */
  120. save_rgid = getgid();
  121. #ifdef _AIX
  122. setregid(getegid(),-1);
  123. #else
  124. setgid(getegid());
  125. #endif /* _AIX */
  126. access_priv = access (fname, what);
  127. #ifdef _AIX
  128. setreuid(save_ruid,-1);
  129. setregid(save_rgid,-1);
  130. #else
  131. setuid(save_ruid);
  132. setgid(save_rgid);
  133. #endif /* _AIX */
  134. return access_priv;
  135. #endif /* BLS */
  136. }
  137. /************************************************************************
  138. *
  139. * FileOperationError
  140. * Display an error message.
  141. *
  142. ************************************************************************/
  143. void
  144. FileOperationError(
  145. Widget w,
  146. char *message1,
  147. char *message2 )
  148. {
  149. char *message_buf;
  150. char * title;
  151. char * tmpStr;
  152. if (message2 != NULL)
  153. {
  154. message_buf = XtMalloc(strlen(message1) + strlen(message2) + 1);
  155. (void) sprintf(message_buf,message1, message2);
  156. }
  157. else
  158. {
  159. message_buf = XtMalloc(strlen(message1) + 1);
  160. (void) sprintf(message_buf, "%s", message1);
  161. }
  162. /* Display an error dialog */
  163. tmpStr = GetSharedMessage(FILE_MANIPULATION_ERROR_TITLE);
  164. title = XtNewString(tmpStr);
  165. _DtMessage (w, title, message_buf, NULL, HelpRequestCB);
  166. XtFree(title);
  167. XtFree(message_buf);
  168. }
  169. /************************************************************************
  170. *
  171. * DName
  172. * Returns the file name of its argument.
  173. * Keep looking thru the string until a "/" is found which still
  174. * has some characters after it.
  175. *
  176. ************************************************************************/
  177. char *
  178. DName(
  179. char *name )
  180. {
  181. char * p;
  182. char * q;
  183. p = q = name;
  184. while (1)
  185. {
  186. q = DtStrchr(q, '/');
  187. if ((q) && *(q+1))
  188. p = q + 1;
  189. if (q == NULL)
  190. break;
  191. q++;
  192. }
  193. return(p);
  194. }
  195. /************************************************************************
  196. *
  197. * Check
  198. *
  199. ************************************************************************/
  200. static int
  201. Check(
  202. Widget w,
  203. char *spth,
  204. ino_t dinode,
  205. int mode,
  206. void (*errorHandler)() )
  207. {
  208. struct stat sbuf;
  209. char filename [MAX_PATH];
  210. char * msg;
  211. char * tmpStr;
  212. sbuf.st_ino = 0;
  213. (void) strcpy (filename, spth);
  214. while (sbuf.st_ino != ROOTINO)
  215. {
  216. if (lstat (filename, &sbuf) < 0)
  217. {
  218. if (errorHandler)
  219. {
  220. tmpStr = (GETMESSAGE(11,33, "Cannot open %s"));
  221. msg = XtNewString(tmpStr);
  222. (*errorHandler) (w, msg, filename);
  223. XtFree(msg);
  224. }
  225. return (False);
  226. }
  227. if (sbuf.st_ino == dinode)
  228. {
  229. if (errorHandler)
  230. {
  231. if (mode == COPY_FILE)
  232. tmpStr = GETMESSAGE(11,35, "Cannot copy a folder into itself.");
  233. else
  234. tmpStr = GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s");
  235. msg = XtNewString(tmpStr);
  236. if (mode == COPY_FILE)
  237. (*errorHandler) (w, msg, NULL);
  238. else
  239. (*errorHandler) (w, msg, filename);
  240. XtFree(msg);
  241. }
  242. return(1);
  243. }
  244. (void) strcat (filename, "/..");
  245. }
  246. return(0);
  247. }
  248. /************************************************************************
  249. *
  250. * MoveDir
  251. *
  252. ************************************************************************/
  253. static Boolean
  254. MoveDir(
  255. Widget w,
  256. char *source,
  257. char *target,
  258. struct stat *sourceStatInfo,
  259. void (*errorHandler)(),
  260. char ** targetRtn ,
  261. int type )
  262. {
  263. static char *pname = "MoveDir";
  264. char *p;
  265. char * targetDir; /* original target dir path */
  266. char *link_path;
  267. int link_result;
  268. struct stat s1; /* status of from file */
  269. struct stat s2; /* status of to file */
  270. char * cptr;
  271. int len, val, val1;
  272. static char buf [BUF_SIZE]; /* generic buffer */
  273. char filename [MAX_PATH]; /* buffer to hold the full file name */
  274. char * msg;
  275. char * tmpStr;
  276. int child_pid, rc;
  277. /* Copy target so we have it for an error dialog if we need it */
  278. targetDir = XtNewString(target);
  279. *targetRtn = NULL;
  280. if ((val = stat (target, &s2)) < 0)
  281. val = lstat(target, &s2);
  282. /* Check if move to itself */
  283. if( sourceStatInfo->st_dev == s2.st_dev)
  284. {
  285. if (Check (w, target, sourceStatInfo->st_ino, MOVE_FILE, NULL ))
  286. return (False);
  287. }
  288. if (val >= 0) /* target exists */
  289. {
  290. if ((s2.st_mode & S_IFMT) != S_IFDIR) /* target not directory */
  291. {
  292. if (errorHandler)
  293. {
  294. char * tmpStr;
  295. tmpStr = GetSharedMessage(CANT_OVERWRITE_ERROR);
  296. msg = XtNewString(tmpStr);
  297. (*errorHandler) (w, msg, target);
  298. XtFree(msg);
  299. }
  300. XtFree(targetDir);
  301. return (False);
  302. }
  303. (void) strcpy (buf, target);
  304. target = buf;
  305. *targetRtn = buf;
  306. DtLastChar(buf, &cptr, &len);
  307. if ((len != 1) || (*cptr != '/'))
  308. (void) strcat (buf, "/");
  309. (void) strcat (buf, DName (source));
  310. if (lstat (target, &s2) >= 0) /* new target exists */
  311. {
  312. if (errorHandler)
  313. {
  314. char * tmpStr;
  315. tmpStr = GetSharedMessage(CANT_OVERWRITE_ERROR);
  316. msg = XtNewString(tmpStr);
  317. (*errorHandler) (w, msg, target);
  318. XtFree(msg);
  319. }
  320. XtFree(targetDir);
  321. return (False);
  322. }
  323. }
  324. p = DName (source);
  325. /* don't rename these */
  326. DtLastChar(p, &cptr, &len);
  327. if (!strcmp (p, ".") || !strcmp (p, "..") ||
  328. !strcmp (p, "") || ((len == 1) && (*cptr == '/')))
  329. {
  330. if (errorHandler)
  331. {
  332. char * tmpStr;
  333. tmpStr = (GETMESSAGE(11,32, "Cannot rename %s"));
  334. msg = XtNewString(tmpStr);
  335. (*errorHandler) (w, msg, p);
  336. XtFree(msg);
  337. }
  338. XtFree(targetDir);
  339. return (False);
  340. }
  341. /* parent doesn't exist */
  342. if((val = stat (_DtPName (source), &s1)) < 0)
  343. val = lstat (_DtPName (source), &s1);
  344. if((val1 = stat (_DtPName (target), &s2)) < 0)
  345. val1 = lstat (_DtPName (target), &s2);
  346. if (val < 0 || val1 < 0)
  347. {
  348. if (errorHandler)
  349. {
  350. tmpStr = GETMESSAGE(11, 14, "Cannot find the folders location.");
  351. msg = XtNewString(tmpStr);
  352. (*errorHandler) (w, msg, NULL);
  353. XtFree(msg);
  354. }
  355. XtFree(targetDir);
  356. return (False);
  357. }
  358. /* check for target parent not writeable */
  359. if (CheckAccess(_DtPName (target), W_OK) == -1)
  360. {
  361. if (errorHandler)
  362. {
  363. char * tmpStr;
  364. tmpStr = GetSharedMessage(CANT_WRITE_ERROR);
  365. msg = XtNewString(tmpStr);
  366. (*errorHandler) (w, msg, targetDir);
  367. XtFree(msg);
  368. }
  369. XtFree(targetDir);
  370. return (False);
  371. }
  372. /* check for source parent not writeable */
  373. if (CheckAccess(_DtPName (source), W_OK) == -1)
  374. {
  375. if (errorHandler)
  376. {
  377. char * tmpStr;
  378. tmpStr = GetSharedMessage(CANT_WRITE_ERROR);
  379. msg = XtNewString(tmpStr);
  380. (*errorHandler) (w, msg, source);
  381. XtFree(msg);
  382. }
  383. XtFree(targetDir);
  384. return (False);
  385. }
  386. /*
  387. if (((sourceStatInfo->st_mode & S_IFMT) == S_IFDIR) &&
  388. (CheckAccess(source, W_OK) != 0))
  389. {
  390. if (errorHandler)
  391. {
  392. char * tmpStr;
  393. tmpStr=GETMESSAGE(11, 57,"You do not have permission to move the folder\n%s\nWrite permission is required.");
  394. msg = XtMalloc(strlen(tmpStr) + strlen(source) + 2);
  395. sprintf(msg, tmpStr, source);
  396. (*errorHandler) (w, msg, source);
  397. XtFree(msg);
  398. }
  399. XtFree(targetDir);
  400. return (False);
  401. }
  402. */
  403. /* if parents are not on the same device, do a copy & delete */
  404. if (s1.st_dev != s2.st_dev)
  405. {
  406. /* Determine correct Geometry Placement fo Move Dialog */
  407. /* @@@ ... to be added */
  408. child_pid = fork();
  409. if (child_pid == -1)
  410. {
  411. if (errorHandler)
  412. {
  413. tmpStr = GETMESSAGE(11, 39, "Cannot create child process.\nThe maximum number of processes for this system has been reached.\nStop some of the processes or programs that are currently\nrunning and then retry this function.");
  414. msg = XtNewString(tmpStr);
  415. (*errorHandler) (w, msg, NULL);
  416. XtFree(msg);
  417. }
  418. XtFree(targetDir);
  419. return False;
  420. }
  421. if (child_pid == 0)
  422. {
  423. DBGFORK(("%s: child forked\n", pname));
  424. /* pass in geometry, and other command lines params when available */
  425. if(type == TRASH_DIRECTORY)
  426. rc = execlp(DTCOPY, "dtfile_copy", "-move", "-confirmReplace",
  427. "-confirmErrors", "-popDown","-checkPerms", source, target, NULL);
  428. else
  429. rc = execlp(DTCOPY, "dtfile_copy", "-move", "-confirmReplace",
  430. "-confirmErrors", "-popDown", source, target, NULL);
  431. /* call errorhandler */
  432. perror ("Could not exec child process \"dtfile_copy\"");
  433. DBGFORK(("%s: child exiting\n", pname));
  434. exit (1);
  435. }
  436. DBGFORK(("%s: forked child<%d>\n", pname, child_pid));
  437. XtFree(targetDir);
  438. return (True);
  439. }
  440. link_path = _DtFollowLink(source);
  441. if (s1.st_ino != s2.st_ino)
  442. { /* different parent inodes */
  443. (void) lstat (source, &s1); /* get source dir ino */
  444. if (Check (w, _DtPName (target), s1.st_ino, MOVE_FILE, errorHandler))
  445. { /* move into self */
  446. XtFree(targetDir);
  447. return(False);
  448. }
  449. }
  450. /* This part of code was implemented with the idea that the links
  451. to be treated differently. So, it has to be uncommented whenever
  452. links are handled differently (i.e., moving a link shall move the
  453. absolute object.
  454. if(strcmp(link_path, source) != 0)
  455. {
  456. if (RunFileCommand (MOVE_CMD, link_path, target, NULL) == 0)
  457. {
  458. XtFree(targetDir);
  459. return (True);
  460. }
  461. }
  462. else
  463. */
  464. {
  465. if (RunFileCommand (MOVE_CMD, source, target, NULL) == 0)
  466. {
  467. XtFree(targetDir);
  468. return (True);
  469. }
  470. }
  471. XtFree(targetDir);
  472. return (False);
  473. }
  474. /************************************************************************
  475. *
  476. * CopyDir
  477. *
  478. ************************************************************************/
  479. static Boolean
  480. CopyDir(
  481. Widget w,
  482. int mode,
  483. char *from,
  484. char *to,
  485. Boolean isContainer,
  486. struct stat *s1,
  487. void (*errorHandler)(),
  488. Boolean checkForBusyDir,
  489. int type )
  490. {
  491. static char *pname = "CopyDir";
  492. char * cptr;
  493. int len;
  494. char target [MAX_PATH]; /* buffer to hold the full file name */
  495. char target_dir [MAX_PATH], target_file [MAX_PATH];
  496. struct stat s2; /* status of to file */
  497. int child_pid, rc, target_rc;
  498. char *msg, *tmpStr;
  499. /* Check if source is readable */
  500. if (CheckAccess(from, R_OK) == -1)
  501. {
  502. if (errorHandler)
  503. {
  504. tmpStr = GetSharedMessage(CANT_READ_ERROR);
  505. msg = XtNewString(tmpStr);
  506. (*errorHandler) (w, msg, from);
  507. XtFree(msg);
  508. }
  509. return (False);
  510. }
  511. /* generate target name */
  512. /* "to" can be something to copy the source into (isContainer=TRUE) */
  513. /* or it can be the full path of the destination (isContainer=FALSE) */
  514. /* the former case is probably more common (e.g. a drag&drop copy) */
  515. /* whereas the second case occurs when, for example, the menu is */
  516. /* to copy directory /u/joe/a to /u/joe/b (not doable with d&d) */
  517. (void) strcpy (target, to);
  518. if (isContainer)
  519. {
  520. DtLastChar(to, &cptr, &len);
  521. if ((len != 1) || (*cptr != '/'))
  522. (void) strcat (target, "/");
  523. (void) strcat (target, DName (from));
  524. }
  525. split_path(target, target_dir, target_file);
  526. /* Check if target directory exists */
  527. if ((target_rc = stat (target, &s2)) < 0)
  528. target_rc = lstat(target, &s2);
  529. if (target_rc >= 0)
  530. {
  531. /* target exists:
  532. * make sure it's a directory */
  533. if ((s2.st_mode & S_IFMT) != S_IFDIR) /* target not directory */
  534. {
  535. if (errorHandler)
  536. {
  537. tmpStr = GetSharedMessage(CANT_OVERWRITE_ERROR);
  538. msg = XtNewString(tmpStr);
  539. (*errorHandler) (w, msg, target);
  540. XtFree(msg);
  541. }
  542. return (False);
  543. }
  544. }
  545. else
  546. {
  547. /* target does not exist:
  548. * make sure the "to" directory exists and is writable */
  549. if ((rc = stat (target_dir, &s2)) < 0)
  550. rc = lstat(target_dir, &s2);
  551. if (rc < 0 || (s2.st_mode & S_IFMT) != S_IFDIR)
  552. {
  553. if (errorHandler)
  554. {
  555. tmpStr = GETMESSAGE(11, 14, "Cannot find the folders location.");
  556. msg = XtNewString(tmpStr);
  557. (*errorHandler) (w, msg, NULL);
  558. XtFree(msg);
  559. }
  560. return (False);
  561. }
  562. if (CheckAccess(target_dir, W_OK) == -1)
  563. {
  564. if (errorHandler)
  565. {
  566. tmpStr = GetSharedMessage(CANT_WRITE_ERROR);
  567. msg = XtNewString(tmpStr);
  568. (*errorHandler) (w, msg, to);
  569. XtFree(msg);
  570. }
  571. return (False);
  572. }
  573. }
  574. /* Determine if we are attempting a copy into self */
  575. if (s1->st_dev == s2.st_dev)
  576. {
  577. if (target_rc >= 0)
  578. {
  579. if (Check (w, to, s1->st_ino, COPY_FILE, errorHandler))
  580. return False;
  581. }
  582. else /* destination dir does not exist, look at its proposed parent */
  583. {
  584. if (Check (w, target_dir, s1->st_ino, COPY_FILE, errorHandler))
  585. return False;
  586. }
  587. }
  588. /* Determine correct Geometry Placement fo Copy Dialog */
  589. /* @@@ ... to be added */
  590. /* If all the above checks have passed, then fork off the copy dialog */
  591. child_pid = fork();
  592. if (child_pid == -1)
  593. {
  594. if (errorHandler)
  595. {
  596. tmpStr = GETMESSAGE(11, 39, "Cannot create child process.\nThe maximum number of processes for this system has been reached.\nStop some of the processes or programs that are currently\nrunning and then retry this function.");
  597. msg = XtNewString(tmpStr);
  598. (*errorHandler) (w, msg, NULL);
  599. XtFree(msg);
  600. }
  601. return False;
  602. }
  603. if (child_pid == 0)
  604. {
  605. DBGFORK(("%s: child forked\n", pname));
  606. /* pass in geometry, and other command lines params when available */
  607. if (mode == MERGE_DIR)
  608. /* merge source & target directories */
  609. rc = execlp(DTCOPY, "dtfile_copy",
  610. "-dontDelete", "-forceCopies", "-copyTop",
  611. "-confirmReplace", "-confirmErrors", "-popDown",
  612. from, target, 0);
  613. else
  614. /* replace target dir */
  615. rc = execlp(DTCOPY, "dtfile_copy",
  616. "-forceCopies", "-copyTop",
  617. "-confirmErrors", "-popDown",
  618. from, target, 0);
  619. /* call errorhandler */
  620. perror ("Could not exec child process \"dtfile_copy\"");
  621. DBGFORK(("%s: child exiting\n", pname));
  622. exit (1);
  623. }
  624. DBGFORK(("%s: forked child<%d>\n", pname, child_pid));
  625. return TRUE;
  626. }
  627. /************************************************************************
  628. *
  629. * FileManip
  630. *
  631. ************************************************************************/
  632. Boolean
  633. FileManip(
  634. Widget w,
  635. int mode,
  636. char *from,
  637. char *to,
  638. Boolean isContainer, /* described in function CopyDir */
  639. void (*errorHandler)(),
  640. Boolean checkForBusyDir,
  641. int type )
  642. {
  643. int fold;
  644. int fnew;
  645. int n;
  646. Boolean copy_dir_return;
  647. Boolean move_dir_return;
  648. void (*oldInt)();
  649. void (*oldQuit)();
  650. void (*oldPipe)();
  651. void (*oldTerm)();
  652. char * cptr;
  653. int len;
  654. Boolean restricted = False;
  655. Boolean fileExists = False;
  656. struct stat s1; /* status of from file e.g. lstat info */
  657. struct stat s4; /* status of from file e.g. stat info */
  658. struct stat s2; /* status of to file e.g. stat info */
  659. struct stat s3; /* status of to file e.g. lstat info */
  660. char buf [BLOCK_SIZE]; /* generic buffer */
  661. char filename [MAX_PATH]; /* buffer to hold the full file name */
  662. char * msg;
  663. int link_result;
  664. char * realTarget;
  665. char * tmpStr;
  666. /* Check the <from> part of the command:
  667. *
  668. * Report error if <from> doesn't exist.
  669. * Else error if <from> hasn't read access.
  670. */
  671. DPRINTF(("FileManip: mode %d type %d from \"%s\" to \"%s\"\n", mode, type, from, to));
  672. if (stat (from, &s1) < 0)
  673. {
  674. if (lstat (from, &s1) < 0)
  675. {
  676. if (errorHandler)
  677. {
  678. tmpStr = (GETMESSAGE(11,28, "%s cannot be found."));
  679. msg = XtNewString(tmpStr);
  680. (*errorHandler) (w, msg, from);
  681. XtFree(msg);
  682. }
  683. return (False);
  684. }
  685. }
  686. /* We will check if we need to initiate a copy of a directory */
  687. if ((s1.st_mode & S_IFMT) == S_IFDIR) /* from is a directory */
  688. {
  689. if (mode == COPY_FILE || mode == MERGE_DIR)
  690. {
  691. oldInt = signal (SIGINT, SIG_IGN);
  692. oldQuit = signal (SIGQUIT, SIG_IGN);
  693. oldPipe = signal (SIGPIPE, SIG_IGN);
  694. oldTerm = signal (SIGTERM, SIG_IGN);
  695. copy_dir_return = CopyDir(w, mode, from, to, isContainer, &s1,
  696. errorHandler, checkForBusyDir, type);
  697. (void) signal (SIGINT, oldInt);
  698. (void) signal (SIGQUIT, oldQuit);
  699. (void) signal (SIGPIPE, oldPipe);
  700. (void) signal (SIGTERM, oldTerm);
  701. return (copy_dir_return);
  702. }
  703. /* If the directory has more than one open view or open views */
  704. /* of sub directories. Then do not allow the move or rename. */
  705. if (mode == MOVE_FILE)
  706. {
  707. if (checkForBusyDir && DirectoryBusy (from))
  708. {
  709. if (errorHandler)
  710. {
  711. char message_buf[512];
  712. char * tmpStr;
  713. message_buf[0] = '\0';
  714. tmpStr = (GETMESSAGE(11,30, "Cannot move or rename the folder %s.\nAll File Manager views displayed for a folder or its sub-folders\nmust be closed before a folder can be moved or renamed."));
  715. sprintf (message_buf, tmpStr, from);
  716. (*errorHandler) (w, message_buf, NULL);
  717. }
  718. return (False);
  719. }
  720. oldInt = signal (SIGINT, SIG_IGN);
  721. oldQuit = signal (SIGQUIT, SIG_IGN);
  722. oldPipe = signal (SIGPIPE, SIG_IGN);
  723. oldTerm = signal (SIGTERM, SIG_IGN);
  724. move_dir_return = MoveDir (w, from, to, &s1, errorHandler, &realTarget,type);
  725. (void) signal (SIGINT, oldInt);
  726. (void) signal (SIGQUIT, oldQuit);
  727. (void) signal (SIGPIPE, oldPipe);
  728. (void) signal (SIGTERM, oldTerm);
  729. return (move_dir_return);
  730. }
  731. if (mode == LINK_FILE)
  732. {
  733. /* Need to append the directory name on */
  734. (void) strcpy(filename, to);
  735. if(type == DESKTOP)
  736. {
  737. char *tmp, *ptr;
  738. tmp = (char *)XtMalloc(strlen(filename) + 1);
  739. strcpy(tmp, filename);
  740. /* get the workspace number first */
  741. ptr = strrchr(tmp, '/');
  742. *ptr = '\0';
  743. /* now get the Desktop */
  744. ptr = strrchr(tmp, '/');
  745. /* if we don't get "/Desktop" then there is another filename
  746. attached to the end of the to name passed in */
  747. if(strcmp(ptr, "/Desktop") != 0)
  748. restricted = True;
  749. XtFree(tmp);
  750. }
  751. if( (!restricted && type != TRASH_DIRECTORY) && isContainer)
  752. {
  753. DtLastChar(to, &cptr, &len);
  754. if ((len != 1) || (*cptr != '/'))
  755. (void) strcat(filename, "/");
  756. }
  757. if(strcmp(from, "/.") == 0 || strcmp(from, "/") == 0)
  758. {
  759. (void) strcat(filename, home_host_name);
  760. (void) strcat(filename, ":");
  761. (void) strcat(filename, root_title);
  762. }
  763. else if ( (!restricted && type != TRASH_DIRECTORY) && isContainer)
  764. (void) strcat(filename, DName(from));
  765. to = filename;
  766. if (((link_result = symlink(from, to)) != 0) && errorHandler)
  767. {
  768. if(type == NOT_DESKTOP || errno != EEXIST )
  769. {
  770. char * tmpStr;
  771. tmpStr = GetSharedMessage(CANT_CREATE_ERROR);
  772. msg = XtNewString(tmpStr);
  773. (*errorHandler) (w, msg, to);
  774. XtFree(msg);
  775. }
  776. }
  777. return(link_result == 0 ? True : False);
  778. }
  779. }
  780. if (CheckAccess(from, R_OK) == -1)
  781. {
  782. /*
  783. * A move operation does not require read permission, but a copy does.
  784. */
  785. if (mode == COPY_FILE)
  786. {
  787. if (errorHandler)
  788. {
  789. char * tmpStr;
  790. tmpStr = GetSharedMessage(CANT_READ_ERROR);
  791. msg = XtNewString(tmpStr);
  792. (*errorHandler) (w, msg, from);
  793. XtFree(msg);
  794. }
  795. return (False);
  796. }
  797. }
  798. /* Here <from> is a file (not a directory).
  799. * Check the <to> part of the command:
  800. *
  801. * <To> can either be an existing file,
  802. * an existing directory,
  803. * or a new file in an existing directory.
  804. */
  805. if (lstat (to, &s2) >= 0) /* <to> exists */
  806. {
  807. if ((stat (to, &s3) >= 0) &&
  808. #if defined(__linux__) || defined(CSRG_BASED)
  809. (((s3.st_mode & S_IFMT) == S_IFDIR) /* if is a directory */
  810. || ((s3.st_mode & S_IFMT) == S_IFSOCK)) ) /* or a net special */
  811. #else
  812. #if defined(SVR4) || defined(_AIX)
  813. ((s3.st_mode & S_IFMT) == S_IFDIR) ) /* if is a directory */
  814. #else /* (__hpux) */
  815. (((s3.st_mode & S_IFMT) == S_IFDIR) /* if is a directory */
  816. || ((s3.st_mode & S_IFMT) == S_IFNWK)) ) /* or a net special */
  817. #endif
  818. #endif
  819. { /* then get file name */
  820. (void) strcpy (filename, to);
  821. DtLastChar(to, &cptr, &len);
  822. if ((len != 1) || (*cptr != '/'))
  823. (void) strcat (filename, "/");
  824. (void) strcat (filename, DName (from));
  825. to = filename;
  826. }
  827. if (lstat (to, &s2) >= 0) /* reverify <to> exists */
  828. {
  829. if ((stat (to, &s3) >= 0) &&
  830. ((s3.st_mode & S_IFMT) == S_IFDIR)) /* if is a directory */
  831. {
  832. if (errorHandler)
  833. {
  834. char * tmpStr;
  835. tmpStr = GetSharedMessage(CANT_OVERWRITE_ERROR);
  836. msg = XtNewString(tmpStr);
  837. (*errorHandler) (w, msg, to);
  838. XtFree(msg);
  839. }
  840. return (False);
  841. }
  842. /* <from> = <to> NOOP. */
  843. if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino)
  844. return (True);
  845. /* no write permission */
  846. if (CheckAccess(to, W_OK) == -1)
  847. {
  848. char *link_path;
  849. link_path = _DtFollowLink(to);
  850. if(strcmp(to,link_path) == 0)
  851. {
  852. if (errorHandler)
  853. {
  854. char * tmpStr;
  855. tmpStr = GetSharedMessage(CANT_OVERWRITE_ERROR);
  856. msg = XtNewString(tmpStr);
  857. (*errorHandler) (w, msg, to);
  858. XtFree(msg);
  859. }
  860. return (False);
  861. }
  862. }
  863. /* unlink failed */
  864. if (unlink (to) < 0)
  865. {
  866. if (errorHandler)
  867. {
  868. char * tmpStr;
  869. tmpStr = GetSharedMessage(CANT_OVERWRITE_ERROR);
  870. msg = XtNewString(tmpStr);
  871. (*errorHandler) (w, msg, to);
  872. XtFree(msg);
  873. }
  874. return (False);
  875. }
  876. fileExists = True;
  877. }
  878. }
  879. /* Here <from> is a file and <to> doesn't exist.
  880. *
  881. * If not a copy, link the files. If the link succeeds, unlink
  882. * <from> and return.
  883. * Copy <from> to <to>.
  884. * If the copy cmd is not specified, unlink <from>.
  885. */
  886. if (mode != COPY_FILE)
  887. {
  888. /* Try to maintain symbolic links, except when we're doing a link! */
  889. if (((s1.st_mode & S_IFMT) == S_IFLNK) && (mode != LINK_FILE))
  890. {
  891. char link_path[MAX_PATH + 1];
  892. int link_len;
  893. if ((link_len = readlink(from, link_path, MAX_PATH)) > 0)
  894. {
  895. link_path[link_len] = '\0';
  896. link_result = symlink(link_path, to);
  897. }
  898. else
  899. {
  900. /* Fail-safe; do it the hard way */
  901. if (mode == MOVE_FILE)
  902. if (RunFileCommand(MOVE_CMD, from, to, NULL) == 0)
  903. return(True);
  904. else
  905. if (RunFileCommand(LINK_CMD, "-s", from, to) == 0)
  906. return(True);
  907. link_result = (-1);
  908. }
  909. }
  910. else
  911. {
  912. if (mode == LINK_FILE)
  913. link_result = symlink(from, to);
  914. else
  915. {
  916. char *link_path;
  917. link_path = _DtFollowLink(from);
  918. if(strcmp(link_path, from) != 0)
  919. link_result = symlink(link_path, to);
  920. else
  921. link_result = link (from, to);
  922. }
  923. }
  924. /* If this was a link, then time to bail out */
  925. if (mode == LINK_FILE)
  926. {
  927. if ((link_result != 0) && errorHandler)
  928. {
  929. char * tmpStr;
  930. tmpStr = GetSharedMessage(CANT_CREATE_ERROR);
  931. msg = XtNewString(tmpStr);
  932. (*errorHandler) (w, msg, to);
  933. XtFree(msg);
  934. }
  935. return(link_result == 0 ? True : False);
  936. }
  937. /* Unlink source only if this was a move request */
  938. if ((mode == MOVE_FILE) && (link_result >= 0))
  939. {
  940. if (unlink (from) < 0)
  941. {
  942. if (errorHandler)
  943. {
  944. char * tmpStr;
  945. tmpStr = GetSharedMessage(CANT_DELETE_ERROR);
  946. msg = XtNewString(tmpStr);
  947. (*errorHandler) (w, msg, from);
  948. XtFree(msg);
  949. }
  950. (void) unlink (to);
  951. return (False);
  952. }
  953. return (True);
  954. }
  955. }
  956. /* unable to read <from> */
  957. if ((fold = open (from, O_RDONLY)) < 0)
  958. {
  959. if (errorHandler)
  960. {
  961. char * tmpStr;
  962. tmpStr = GetSharedMessage(CANT_READ_ERROR);
  963. msg = XtNewString(tmpStr);
  964. (*errorHandler) (w, msg, from);
  965. XtFree(msg);
  966. }
  967. return (False);
  968. }
  969. /* unable create <to> */
  970. /* We use the stat buffer info not lstat info */
  971. (void) stat (from, &s4);
  972. if ((fnew = creat (to, (int) s4.st_mode)) < 0)
  973. {
  974. if (errorHandler)
  975. {
  976. char * tmpStr;
  977. tmpStr = GetSharedMessage(CANT_CREATE_ERROR);
  978. msg = XtNewString(tmpStr);
  979. (*errorHandler) (w, msg, to);
  980. XtFree(msg);
  981. }
  982. (void) close (fold);
  983. return (False);
  984. }
  985. /* do the copy */
  986. while (n = read (fold, buf, BLOCK_SIZE))
  987. {
  988. int result;
  989. if (n < 0)
  990. {
  991. if (errorHandler)
  992. {
  993. tmpStr = (GETMESSAGE(11,31, "Error while reading %s"));
  994. msg = XtNewString(tmpStr);
  995. (*errorHandler) (w, msg, to);
  996. XtFree(msg);
  997. }
  998. (void) close (fold);
  999. (void) close (fnew);
  1000. return (False);
  1001. }
  1002. errno = 0;
  1003. result = write(fnew, buf, n);
  1004. if (result != n)
  1005. {
  1006. (void) close (fold);
  1007. (void) close (fnew);
  1008. if(errno)
  1009. {
  1010. char * strerrormsg = NULL;
  1011. char * catmsg = NULL;
  1012. char * samsg = NULL;
  1013. char errnoMsg[25];
  1014. Boolean unknown = False;
  1015. int bufLen;
  1016. switch (errno)
  1017. {
  1018. #ifdef EDQUOT
  1019. case EDQUOT:
  1020. {
  1021. if(mode == COPY_FILE)
  1022. tmpStr = (GETMESSAGE(11,51, "Unable to copy the file/folder because\nthe disk quota will be exceeded on the disk\nyou are copying it to."));
  1023. else
  1024. tmpStr = (GETMESSAGE(11,52, "Unable to move the file/folder because\nthe disk quota will be exceeded on the disk\nyou are moving it to."));
  1025. catmsg = XtNewString(tmpStr);
  1026. break;
  1027. }
  1028. #endif
  1029. case ENOSPC:
  1030. {
  1031. if(mode == COPY_FILE)
  1032. tmpStr = (GETMESSAGE(11,42, "No space available on the\ndevice you are copying to.\n\n"));
  1033. else
  1034. tmpStr = (GETMESSAGE(11,43, "No space available on the\ndevice you are moving to.\n"));
  1035. catmsg = XtNewString(tmpStr);
  1036. break;
  1037. }
  1038. case EAGAIN:
  1039. sprintf(errnoMsg, "EAGAIN: ");
  1040. strerrormsg = strerror(errno);
  1041. break;
  1042. case EBADF:
  1043. sprintf(errnoMsg, "EBADF: ");
  1044. strerrormsg = strerror(errno);
  1045. break;
  1046. case EDEADLK:
  1047. sprintf(errnoMsg, "EDEADLK: ");
  1048. strerrormsg = strerror(errno);
  1049. break;
  1050. case EINTR:
  1051. sprintf(errnoMsg, "EINTR: ");
  1052. strerrormsg = strerror(errno);
  1053. break;
  1054. case EIO:
  1055. sprintf(errnoMsg, "EIO: ");
  1056. strerrormsg = strerror(errno);
  1057. break;
  1058. case ENOLCK:
  1059. sprintf(errnoMsg, "ENOLCK: ");
  1060. strerrormsg = strerror(errno);
  1061. break;
  1062. case EPIPE:
  1063. sprintf(errnoMsg, "EPIPE: ");
  1064. strerrormsg = strerror(errno);
  1065. break;
  1066. default:
  1067. unknown = True;
  1068. sprintf(errnoMsg, "%s", GETMESSAGE(11,56, "(Unknown):"));
  1069. strerrormsg = strerror(errno);
  1070. break;
  1071. }
  1072. /* If catmsg is NULL then one of the miscellanous error's occurred.
  1073. * Set up a generic error message which will output the internal
  1074. * error message.
  1075. */
  1076. if(catmsg == NULL)
  1077. {
  1078. if(mode == COPY_FILE)
  1079. tmpStr = (GETMESSAGE(11,53, "The copy of the file/folder failed\ndue to some internal error. The internal\nerror given is:"));
  1080. else
  1081. tmpStr = (GETMESSAGE(11,54, "The move of the file/folder failed\ndue to some internal error. The internal\nerror given is:"));
  1082. catmsg = XtNewString(tmpStr);
  1083. tmpStr = (GETMESSAGE(11,55, "Please see your System Administrator"));
  1084. samsg = XtNewString(tmpStr);
  1085. }
  1086. /* Build a concatination of the possible message parts */
  1087. bufLen = (strerrormsg ? strlen(strerrormsg) +
  1088. strlen(errnoMsg) + strlen(samsg) : 0) +
  1089. strlen(catmsg) + 10;
  1090. msg = XtMalloc(bufLen);
  1091. strcpy (msg, catmsg);
  1092. if (strerrormsg)
  1093. {
  1094. strcat (msg, "\n\n");
  1095. strcat (msg, errnoMsg);
  1096. if(unknown)
  1097. strcat (msg, " ");
  1098. strcat (msg, strerrormsg);
  1099. strcat (msg, "\n\n");
  1100. strcat (msg, samsg);
  1101. }
  1102. (*errorHandler) (w, msg, to);
  1103. XtFree(msg);
  1104. XtFree(catmsg);
  1105. }
  1106. unlink(to);
  1107. return (False);
  1108. }
  1109. }
  1110. (void) close (fold);
  1111. (void) close (fnew);
  1112. /* unlink <from> if not copy */
  1113. if (mode == MOVE_FILE)
  1114. {
  1115. if (unlink (from) < 0)
  1116. {
  1117. if (errorHandler)
  1118. {
  1119. char *tmpStr, *ptr;
  1120. ptr = strrchr(from, '/') + 1;
  1121. tmpStr = (GETMESSAGE(11,38, "You do not have permission to move %s\nHowever, you can copy the object.\nTo copy an object:\n - press and hold the <Ctrl> key, and\n - drag the object with your mouse.\nOr\n - use 'Copy To' in the 'Selected' menu popup of the menu bar."));
  1122. msg = XtNewString(tmpStr);
  1123. (*errorHandler) (w, msg, ptr);
  1124. XtFree(msg);
  1125. unlink(to);
  1126. }
  1127. return (False);
  1128. }
  1129. }
  1130. /*
  1131. * WARNING: this is different from how the shell behaves. If you use
  1132. * a shell to copy over an existing file, the file keeps its
  1133. * original owner and group; for some historical reason,
  1134. * dtfile does it differently.
  1135. * UPDATE: This is no longer the case as of 10/31/94, we change the
  1136. * file to the original owner and group now. This is to fix
  1137. * a bug.
  1138. * Also, this call originally occurred after we opened/created
  1139. * the file, but before we closed it. This caused problems
  1140. * if the user was running as root, and was copying across
  1141. * an nfs link, since root access is not typically carried
  1142. * across an nfs mount. The result was that we were able to
  1143. * create the file, copy to it, but when we tried to close it,
  1144. * because the file was now owned by root on the other system,
  1145. * we could not close the file; thus, the file ended up empty!
  1146. */
  1147. if (mode == COPY_FILE && fileExists)
  1148. {
  1149. /* set for user */
  1150. (void) chmod (to, s3.st_mode);
  1151. (void) chown (to, s3.st_uid, s3.st_gid);
  1152. }
  1153. else
  1154. {
  1155. /* set for user */
  1156. (void) chown (to, getuid(), getgid());
  1157. }
  1158. return (True);
  1159. }