mv.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. int copy1(int fdf, int fdt, char *from, char *to);
  12. void hardremove(char *);
  13. int mv(char *from, char *todir, char *toelem);
  14. int mv1(char *from, Dir *dirb, char *todir, char *toelem);
  15. int samefile(char *, char *);
  16. void split(char *, char **, char **);
  17. void
  18. main(int argc, char *argv[])
  19. {
  20. int i, failed;
  21. Dir *dirto, *dirfrom;
  22. char *todir, *toelem;
  23. if(argc<3){
  24. fprint(2, "usage: mv fromfile tofile\n");
  25. fprint(2, " mv fromfile ... todir\n");
  26. exits("bad usage");
  27. }
  28. /* prepass to canonicalise names before splitting, etc. */
  29. for(i=1; i < argc; i++)
  30. cleanname(argv[i]);
  31. if((dirto = dirstat(argv[argc-1])) != nil && (dirto->mode&DMDIR)){
  32. dirfrom = nil;
  33. if(argc == 3
  34. && (dirfrom = dirstat(argv[1])) != nil
  35. && (dirfrom->mode & DMDIR))
  36. split(argv[argc-1], &todir, &toelem); /* mv dir1 dir2 */
  37. else{ /* mv file... dir */
  38. todir = argv[argc-1];
  39. toelem = nil; /* toelem will be fromelem */
  40. }
  41. free(dirfrom);
  42. }else
  43. split(argv[argc-1], &todir, &toelem); /* mv file1 file2 */
  44. free(dirto);
  45. if(argc>3 && toelem != nil){
  46. fprint(2, "mv: %s not a directory\n", argv[argc-1]);
  47. exits("bad usage");
  48. }
  49. failed = 0;
  50. for(i=1; i < argc-1; i++)
  51. if(mv(argv[i], todir, toelem) < 0)
  52. failed++;
  53. if(failed)
  54. exits("failure");
  55. exits(0);
  56. }
  57. int
  58. mv(char *from, char *todir, char *toelem)
  59. {
  60. int stat;
  61. Dir *dirb;
  62. dirb = dirstat(from);
  63. if(dirb == nil){
  64. fprint(2, "mv: can't stat %s: %r\n", from);
  65. return -1;
  66. }
  67. stat = mv1(from, dirb, todir, toelem);
  68. free(dirb);
  69. return stat;
  70. }
  71. int
  72. mv1(char *from, Dir *dirb, char *todir, char *toelem)
  73. {
  74. int fdf, fdt, i, j, stat;
  75. char toname[4096], fromname[4096];
  76. char *fromdir, *fromelem;
  77. Dir *dirt, null;
  78. strncpy(fromname, from, sizeof fromname);
  79. split(from, &fromdir, &fromelem);
  80. if(toelem == 0)
  81. toelem = fromelem;
  82. i = strlen(toelem);
  83. if(i==0){
  84. fprint(2, "mv: null last name element moving %s\n", fromname);
  85. return -1;
  86. }
  87. j = strlen(todir);
  88. if(i + j + 2 > sizeof toname){
  89. fprint(2, "mv: path too big (max %d): %s/%s\n",
  90. sizeof toname, todir, toelem);
  91. return -1;
  92. }
  93. memmove(toname, todir, j);
  94. toname[j] = '/';
  95. memmove(toname+j+1, toelem, i);
  96. toname[i+j+1] = 0;
  97. if(samefile(fromdir, todir)){
  98. if(samefile(fromname, toname)){
  99. fprint(2, "mv: %s and %s are the same\n",
  100. fromname, toname);
  101. return -1;
  102. }
  103. /* remove target if present */
  104. dirt = dirstat(toname);
  105. if(dirt != nil) {
  106. hardremove(toname);
  107. free(dirt);
  108. }
  109. /* try wstat */
  110. nulldir(&null);
  111. null.name = toelem;
  112. if(dirwstat(fromname, &null) >= 0)
  113. return 0;
  114. if(dirb->mode & DMDIR){
  115. fprint(2, "mv: can't rename directory %s: %r\n",
  116. fromname);
  117. return -1;
  118. }
  119. }
  120. /*
  121. * Renaming won't work --- must copy
  122. */
  123. if(dirb->mode & DMDIR){
  124. fprint(2, "mv: %s is a directory, not copied to %s\n",
  125. fromname, toname);
  126. return -1;
  127. }
  128. fdf = open(fromname, OREAD);
  129. if(fdf < 0){
  130. fprint(2, "mv: can't open %s: %r\n", fromname);
  131. return -1;
  132. }
  133. dirt = dirstat(toname);
  134. if(dirt != nil && (dirt->mode & DMAPPEND))
  135. hardremove(toname); /* because create() won't truncate file */
  136. free(dirt);
  137. fdt = create(toname, OWRITE, dirb->mode);
  138. if(fdt < 0){
  139. fprint(2, "mv: can't create %s: %r\n", toname);
  140. close(fdf);
  141. return -1;
  142. }
  143. stat = copy1(fdf, fdt, fromname, toname);
  144. close(fdf);
  145. if(stat >= 0){
  146. nulldir(&null);
  147. null.mtime = dirb->mtime;
  148. null.mode = dirb->mode;
  149. dirfwstat(fdt, &null); /* ignore errors; e.g. user none always fails */
  150. if(remove(fromname) < 0){
  151. fprint(2, "mv: can't remove %s: %r\n", fromname);
  152. stat = -1;
  153. }
  154. }
  155. close(fdt);
  156. return stat;
  157. }
  158. int
  159. copy1(int fdf, int fdt, char *from, char *to)
  160. {
  161. char buf[8192];
  162. int32_t n, n1;
  163. while ((n = read(fdf, buf, sizeof buf)) > 0) {
  164. n1 = write(fdt, buf, n);
  165. if(n1 != n){
  166. fprint(2, "mv: error writing %s: %r\n", to);
  167. return -1;
  168. }
  169. }
  170. if(n < 0){
  171. fprint(2, "mv: error reading %s: %r\n", from);
  172. return -1;
  173. }
  174. return 0;
  175. }
  176. void
  177. split(char *name, char **pdir, char **pelem)
  178. {
  179. char *s;
  180. s = utfrrune(name, '/');
  181. if(s){
  182. *s = 0;
  183. *pelem = s+1;
  184. *pdir = name;
  185. }else if(strcmp(name, "..") == 0){
  186. *pdir = "..";
  187. *pelem = ".";
  188. }else{
  189. *pdir = ".";
  190. *pelem = name;
  191. }
  192. }
  193. int
  194. samefile(char *a, char *b)
  195. {
  196. Dir *da, *db;
  197. int ret;
  198. if(strcmp(a, b) == 0)
  199. return 1;
  200. da = dirstat(a);
  201. db = dirstat(b);
  202. ret = (da != nil && db != nil &&
  203. da->qid.type==db->qid.type &&
  204. da->qid.path==db->qid.path &&
  205. da->qid.vers==db->qid.vers &&
  206. da->dev==db->dev &&
  207. da->type==db->type);
  208. free(da);
  209. free(db);
  210. return ret;
  211. }
  212. void
  213. hardremove(char *a)
  214. {
  215. if(remove(a) == -1){
  216. fprint(2, "mv: can't remove %s: %r\n", a);
  217. exits("mv");
  218. }
  219. while(remove(a) != -1)
  220. ;
  221. }