/* a public domain rename, by ERS */ #include #include #include #include #include #include #include #include "symdir.h" int rename(_oldname, _newname) const char *_oldname, *_newname; { char oldname[FILENAME_MAX], newname[FILENAME_MAX]; char oldpath[FILENAME_MAX]; int rval, name_munged; SYMDIR *olddir = 0, *newdir = 0; SYMENTRY *ent = 0, *old; char *s; int save_errno = errno; if (!access(_newname, 0)) { /* new name already exists */ #ifdef DEBUG printf("rename: unlinking %s\n", _newname); #endif if (unlink(_newname)) return -1; } errno = save_errno; rval = _unx2dos(_oldname, oldname); /* _unx2dos returns _NM_LINK and sets __link_path and __link_name if * given a symbolic link */ if (rval == _NM_LINK) { /* a symbolic link */ strcpy(oldpath, __link_path); /* save path to symlink */ olddir = _read_symdir(oldpath); if (!olddir) return -1; old = 0; ent = olddir->s_dir; while (ent) { if (!strcmp(ent->linkname, __link_name)) { #ifdef DEBUG printf("rename: found symbolic link %s\n", __link_name); #endif break; } old = ent; ent = ent->next; } if (!ent) { errno = EERROR; _free_symdir(olddir); return -1; } if (old) old->next = ent->next; else olddir->s_dir = ent->next; ent->next = 0; _write_symdir(oldpath, olddir); _free_symdir(olddir); } /* * save info about whether or not the name got changed by _unx2dos */ name_munged = (_unx2dos(_newname, newname) == _NM_CHANGE); /* * for a symbolic link, we now have an entry "ent" which points at * the old symbolic link. Make a new symbolic link, with the new name, * in the new directory. EXCEPTION: automatic symbolic links get handled * later. */ if (ent && !(ent->flags & SD_AUTO)) { if ((s = strrchr(newname, '\\'))) *s = 0; if (!s || !(newdir = _read_symdir(newname))) { link_failed: #ifdef DEBUG printf("rename: attempt to link to directory %s failed\n", newname); #endif /* if we can't put the symlink into the new directory, put it * back in the old one again */ olddir = _read_symdir(oldpath); if (olddir) { ent->next = olddir->s_dir; olddir->s_dir = ent; _write_symdir(oldpath, olddir); _free_symdir(olddir); } return -1; } /* OK, now allocate a new symentry to hold the new name and link * info. Note that "old" is definitely a misnomer here!!! */ old = (SYMENTRY *)malloc(3+sizeof(SYMENTRY)+ strlen(__link_name)+strlen(ent->linkto)+strlen(ent->cflags) ); if (!old) { errno = ENOMEM; goto link_failed; } /* * Now copy all the fields of "ent" into the new symentry * (which is, contrary to reason, called "old"; actually, this * is so that on an error we can "goto link_failed" and restore * the status quo). */ s = old->linkname; strcpy(old->linkname, __link_name); s += strlen(__link_name)+1; old->linkto = s; strcpy(s, ent->linkto); s += strlen(ent->linkto)+1; old->cflags = s; strcpy(s, ent->cflags); free(ent); old->next = newdir->s_dir; newdir->s_dir = old; /* * update the copy on disk, and return */ #ifdef DEBUG printf("rename: updating symbolic link info\n"); #endif rval = _write_symdir(newname, newdir); _free_symdir(newdir); if (rval) { errno = -rval; return -1; } return 0; } /* * normal files, and automatic symbolic links, come here */ #ifdef DEBUG printf("rename: calling Frename(%s, %s)\n", oldname, newname); #endif if (!strcmp(oldname, newname)) { rval = 0; } else if ( (rval = Frename(0, oldname, newname)) < 0 ) { errno = -rval; /* set errno now for link_failed */ rval = -1; } if (ent) { if (rval < 0) goto link_failed; else { free(ent); ent = 0; } } /* * finally, check to see if the new name should have an automatic symbolic * link attached */ if (rval == 0 && name_munged) _make_autolink(newname, __link_name); return rval; }