mv.c 4.1 KB

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