shithub: riscv

ref: 04c3a6f66e3b895a087124ed415f01e23e21ee10
dir: /sys/src/ape/lib/ap/plan9/unlink.c/

View raw version
#include "lib.h"
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sys9.h"
#include "dir.h"


/*
 * BUG: errno mapping
 */

int
unlink(const char *path)
{
	int n, i, fd;
	long long nn;
	Dir *db1, *db2, nd;
	Fdinfo *f;
 	char *p, *newname, newelem[32];

	/* if the file is already open, make it close-on-exec (and rename to qid) */
	if((db1 = _dirstat(path)) == nil) {
		_syserrno();
		return -1;
	}
	fd = -1;
	for(i=0, f = _fdinfo;i < OPEN_MAX; i++, f++) {
		if((f->flags&FD_ISOPEN) && (db2=_dirfstat(i)) != nil) {
			if(db1->qid.path == db2->qid.path &&
			   db1->qid.vers == db2->qid.vers &&
			   db1->type == db2->type &&
			   db1->dev == db2->dev) {
				newname = 0;
				sprintf(newelem, "%8.8lx%8.8lx",
					(ulong)(db2->qid.path>>32),
					(ulong)db2->qid.path);
				_nulldir(&nd);
				nd.name = newelem;
				if(_dirfwstat(i, &nd) < 0)
					p = (char*)path;
				else {
					p = strrchr(path, '/');
					if(p == 0)
						p = newelem; 
					else {
						n = p-path;
						newname = malloc(n+1+sizeof(newelem));
						if(newname == 0){
							free(db2);
							free(db1);
							return -1;
						}
						memmove(newname, path, n);
						newname[n] = '/';
						strcpy(newname+n+1, newelem);
						p = newname;
					}
				}
				/* reopen remove on close */
				fd = _OPEN(p, ORCLOSE|(f->oflags));
				if(fd < 0){
					free(newname);
					free(db2);
					continue;
				}
				nn = _SEEK(i, 0, 1);
				if(nn < 0)
					nn = 0;
				_SEEK(fd, nn, 0);
				_DUP(fd, i);
				_CLOSE(fd);
				free(newname);
				free(db2);
				free(db1);
				return 0;
			}
			free(db2);
		}
	}
	if(fd == -1)
		if((n=_REMOVE(path)) < 0)
			_syserrno();
	free(db1);
	return n;
}