summaryrefslogtreecommitdiff
path: root/sys/src/ape/lib/ap/plan9/rename.c
blob: c02948316e548fd2a9477d8100177ddb4ced2c2d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include "lib.h"
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "sys9.h"
#include "dir.h"

int
rename(const char *from, const char *to)
{
	int n, ffd, tfd;
	char *f, *t;
	Dir *d, nd;

	if(access(to, 0) >= 0){
		if(_REMOVE(to) < 0){
			_syserrno();
			return -1;
		}
	}
	if((d = _dirstat(to)) != nil){
		free(d);
		errno = EEXIST;
		return -1;
	}
	if((d = _dirstat(from)) == nil){
		_syserrno();
		return -1;
	}
	f = strrchr(from, '/');
	t = strrchr(to, '/');
	f = f? f+1 : (char*)from;
	t = t? t+1 : (char*)to;
	if(f-from==t-to && strncmp(from, to, f-from)==0){
		/* from and to are in same directory (we miss some cases) */
		_nulldir(&nd);
		nd.name = t;
		if(_dirwstat(from, &nd) < 0){
			_syserrno();
			return -1;
		}
	}else{
		/* different directories: have to copy */
		char buf[8192];


		if((ffd = _OPEN(from, OREAD)) == -1)
			goto err1;
		if((tfd = _CREATE(to, OWRITE, d->mode)) == -1)
			goto err2;
		n = 0;
		while(n>=0){
			if((n = _READ(ffd, buf, sizeof(buf))) == -1)
				goto err2;
			if(_WRITE(tfd, buf, n) != n)
				goto err2;
		}
		_CLOSE(ffd);
		_CLOSE(tfd);
		if(_REMOVE(from) < 0)
			goto err2;
	}
	free(d);
	return 0;

err2:
	_CLOSE(tfd);
err1:
	_CLOSE(ffd);
	_syserrno();
	free(d);
	return -1;
}