changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > plan9front / changeset: ape: reimplement rename() - fixing compiler warnings and handling more error cases

changeset 7299: 2c3cb67101c4
parent 7298: 1d4da8ed4cb1
child 7300: 6228acd5dfd1
author: cinap_lenrek@felloff.net
date: Mon, 24 Jun 2019 20:09:04 +0200
files: sys/src/ape/lib/ap/plan9/rename.c
description: ape: reimplement rename() - fixing compiler warnings and handling more error cases

handle empty filename, dot and dotdot. handle mismatching from/to directory/file
type. cleanup destination file on error. error when attempting to copy non-empty
directories.

little test program:

#include <unistd.h>
#include <stdio.h>

int
main(int argc, char *argv[])
{
if(argc != 3){
fprintf(stderr, "usage: %s old new\n", argv[0]);
return 1;
}
if(rename(argv[1], argv[2])){
perror("rename");
return 1;
}
return 0;
}
     1.1--- a/sys/src/ape/lib/ap/plan9/rename.c
     1.2+++ b/sys/src/ape/lib/ap/plan9/rename.c
     1.3@@ -10,66 +10,92 @@
     1.4 int
     1.5 rename(const char *from, const char *to)
     1.6 {
     1.7-	int n, i;
     1.8-	char *f, *t;
     1.9-	Dir *d, nd;
    1.10+	char buf[8192], *f, *t;
    1.11+	Dir *s, *d, nd;
    1.12+	int n, ffd, tfd;
    1.13 
    1.14-	if(access(to, 0) >= 0){
    1.15-		if(_REMOVE(to) < 0){
    1.16-			_syserrno();
    1.17-			return -1;
    1.18-		}
    1.19-	}
    1.20-	if((d = _dirstat(to)) != nil){
    1.21-		free(d);
    1.22-		errno = EEXIST;
    1.23+	f = strrchr(from, '/');
    1.24+	t = strrchr(to, '/');
    1.25+	f = f != nil ? f+1 : (char*)from;
    1.26+	t = t != nil ? t+1 : (char*)to;
    1.27+
    1.28+	if(*f == '\0' || strcmp(f, ".") == 0 || strcmp(f, "..") == 0
    1.29+	|| *t == '\0' || strcmp(t, ".") == 0 || strcmp(t, "..") == 0){
    1.30+		errno = EINVAL;
    1.31 		return -1;
    1.32 	}
    1.33-	if((d = _dirstat(from)) == nil){
    1.34+
    1.35+	if((s = _dirstat(from)) == nil){
    1.36 		_syserrno();
    1.37 		return -1;
    1.38 	}
    1.39-	f = strrchr(from, '/');
    1.40-	t = strrchr(to, '/');
    1.41-	f = f? f+1 : from;
    1.42-	t = t? t+1 : to;
    1.43-	n = 0;
    1.44+	if((d = _dirstat(to)) != nil){
    1.45+		if(d->qid.type == s->qid.type
    1.46+		&& d->qid.path == s->qid.path
    1.47+		&& d->qid.vers == s->qid.vers
    1.48+		&& d->type == s->type
    1.49+		&& d->dev == s->dev)
    1.50+			goto out;	/* same file */
    1.51+
    1.52+		if((d->mode ^ s->mode) & DMDIR){
    1.53+			errno = (d->mode & DMDIR) ? EISDIR : ENOTDIR;
    1.54+			goto err;
    1.55+		}
    1.56+	}
    1.57+
    1.58+	/* from and to are in same directory (we miss some cases) */
    1.59 	if(f-from==t-to && strncmp(from, to, f-from)==0){
    1.60-		/* from and to are in same directory (we miss some cases) */
    1.61-		i = strlen(t);
    1.62+		if(d != nil && _REMOVE(to) < 0){
    1.63+			_syserrno();
    1.64+			goto err;
    1.65+		}
    1.66 		_nulldir(&nd);
    1.67 		nd.name = t;
    1.68 		if(_dirwstat(from, &nd) < 0){
    1.69 			_syserrno();
    1.70-			n = -1;
    1.71-		}
    1.72-	}else{
    1.73-		/* different directories: have to copy */
    1.74-		int ffd, tfd;
    1.75-		char buf[8192];
    1.76-
    1.77-		if((ffd = _OPEN(from, OREAD)) < 0 ||
    1.78-		   (tfd = _CREATE(to, OWRITE, d->mode)) < 0){
    1.79-			_CLOSE(ffd);
    1.80-			_syserrno();
    1.81-			n = -1;
    1.82+			goto err;
    1.83 		}
    1.84-		while(n>=0 && (n = _READ(ffd, buf, sizeof(buf))) > 0)
    1.85-			if(_WRITE(tfd, buf, n) != n){
    1.86-				_syserrno();
    1.87-				n = -1;
    1.88-			}
    1.89+		goto out;
    1.90+	}
    1.91+
    1.92+	/* different directories: have to copy */
    1.93+	if((ffd = _OPEN(from, OREAD)) < 0){
    1.94+		_syserrno();
    1.95+		goto err;
    1.96+	}
    1.97+	if((s->mode & DMDIR) != 0 && _READ(ffd, buf, sizeof(buf)) > 0){
    1.98+		/* cannot copy non-empty directories */
    1.99+		errno = EXDEV;
   1.100+		_CLOSE(ffd);
   1.101+		goto err;
   1.102+	}
   1.103+	if(d != nil && _REMOVE(to) < 0){
   1.104+		_syserrno();
   1.105+		_CLOSE(ffd);
   1.106+		goto err;
   1.107+	}
   1.108+	if((tfd = _CREATE(to, OWRITE, s->mode)) < 0){
   1.109+		_syserrno();
   1.110 		_CLOSE(ffd);
   1.111-		_CLOSE(tfd);
   1.112-		if(n>0)
   1.113-			n = 0;
   1.114-		if(n == 0) {
   1.115-			if(_REMOVE(from) < 0){
   1.116-				_syserrno();
   1.117-				return -1;
   1.118-			}
   1.119-		}
   1.120+		goto err;
   1.121+	}
   1.122+	while((n = _READ(ffd, buf, sizeof(buf))) > 0){
   1.123+		if(_WRITE(tfd, buf, n) != n)
   1.124+			break;
   1.125 	}
   1.126+	_CLOSE(ffd);
   1.127+	_CLOSE(tfd);
   1.128+	if(n != 0 || _REMOVE(from) < 0){
   1.129+		_syserrno();
   1.130+		_REMOVE(to);	/* cleanup */
   1.131+		goto err;
   1.132+	}
   1.133+out:
   1.134+	free(s);
   1.135 	free(d);
   1.136-	return n;
   1.137+	return 0;
   1.138+err:
   1.139+	free(s);
   1.140+	free(d);
   1.141+	return -1;
   1.142 }