mv.c 4.6 KB

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