kernel/sysfile.c
uint64
sys_rename(void)
{
  char old[FAT32_MAX_PATH], new[FAT32_MAX_PATH];
  if (argstr(0, old, FAT32_MAX_PATH) < 0 || argstr(1, new, FAT32_MAX_PATH) < 0) {
      return -1;
  }

  struct dirent *src = NULL, *dst = NULL, *pdst = NULL;
  int srclock = 0;
  char *name;
  if ((src = ename(old)) == NULL || (pdst = enameparent(new, old)) == NULL
      || (name = formatname(old)) == NULL) {
    goto fail;          // src doesn't exist || dst parent doesn't exist || illegal new name
  }
  for (struct dirent *ep = pdst; ep != NULL; ep = ep->parent) {
    if (ep == src) {    // In what universe can we move a directory into its child?
      goto fail;
    }
  }

  uint off;
  elock(src);     // must hold child's lock before acquiring parent's, because we do so in other similar cases
  srclock = 1;
  elock(pdst);
  dst = dirlookup(pdst, name, &off);
  if (dst != NULL) {
    eunlock(pdst);
    if (src == dst) {
      goto fail;
    } else if (src->attribute & dst->attribute & ATTR_DIRECTORY) {
      elock(dst);
      if (!isdirempty(dst)) {    // it's ok to overwrite an empty dir
        eunlock(dst);
        goto fail;
      }
      elock(pdst);
    } else {                    // src is not a dir || dst exists and is not an dir
      goto fail;
    }
  }

  if (dst) {
    eremove(dst);
    eunlock(dst);
  }
  memmove(src->filename, name, FAT32_MAX_FILENAME);
  emake(pdst, src, off);
  if (src->parent != pdst) {
    eunlock(pdst);
    elock(src->parent);
  }
  eremove(src);
  eunlock(src->parent);
  struct dirent *psrc = src->parent;  // src must not be root, or it won't pass the for-loop test
  src->parent = edup(pdst);
  src->off = off;
  src->valid = 1;
  eunlock(src);

  eput(psrc);
  if (dst) {
    eput(dst);
  }
  eput(pdst);
  eput(src);

  return 0;

fail:
  if (srclock)
    eunlock(src);
  if (dst)
    eput(dst);
  if (pdst)
    eput(pdst);
  if (src)
    eput(src);
  return -1;
}
// Must hold too many locks at a time! It's possible to raise a deadlock.
// Because this op takes some steps, we can't promise
Must hold too many locks at a time. It's possible to raise a deadlock.
Because this op takes some steps, we can't promise
Must hold too many locks at a time . It ' s possible to raise a deadlock . Because this op takes some steps we can ' t promise
uint64
sys_rename(void)
{
  char old[FAT32_MAX_PATH], new[FAT32_MAX_PATH];
  if (argstr(0, old, FAT32_MAX_PATH) < 0 || argstr(1, new, FAT32_MAX_PATH) < 0) {
      return -1;
  }
  struct dirent *src = NULL, *dst = NULL, *pdst = NULL;
  int srclock = 0;
  char *name;
  if ((src = ename(old)) == NULL || (pdst = enameparent(new, old)) == NULL
      || (name = formatname(old)) == NULL) {
    goto fail;          
  }
  for (struct dirent *ep = pdst; ep != NULL; ep = ep->parent) {
    if (ep == src) {    
      goto fail;
    }
  }
  uint off;
  elock(src);     
  srclock = 1;
  elock(pdst);
  dst = dirlookup(pdst, name, &off);
  if (dst != NULL) {
    eunlock(pdst);
    if (src == dst) {
      goto fail;
    } else if (src->attribute & dst->attribute & ATTR_DIRECTORY) {
      elock(dst);
      if (!isdirempty(dst)) {    
        eunlock(dst);
        goto fail;
      }
      elock(pdst);
    } else {                    
      goto fail;
    }
  }
  if (dst) {
    eremove(dst);
    eunlock(dst);
  }
  memmove(src->filename, name, FAT32_MAX_FILENAME);
  emake(pdst, src, off);
  if (src->parent != pdst) {
    eunlock(pdst);
    elock(src->parent);
  }
  eremove(src);
  eunlock(src->parent);
  struct dirent *psrc = src->parent;  
  src->parent = edup(pdst);
  src->off = off;
  src->valid = 1;
  eunlock(src);
  eput(psrc);
  if (dst) {
    eput(dst);
  }
  eput(pdst);
  eput(src);
  return 0;
fail:
  if (srclock)
    eunlock(src);
  if (dst)
    eput(dst);
  if (pdst)
    eput(pdst);
  if (src)
    eput(src);
  return -1;
}
uint64 sys_rename ( void ) { char old [ FAT32_MAX_PATH ] , new [ FAT32_MAX_PATH ] ; if ( argstr ( 0 , old , FAT32_MAX_PATH ) < 0 || argstr ( 1 , new , FAT32_MAX_PATH ) < 0 ) { return -1 ; } struct dirent * src = NULL , * dst = NULL , * pdst = NULL ; int srclock = 0 ; char * name ; if ( ( src = ename ( old ) ) == NULL || ( pdst = enameparent ( new , old ) ) == NULL || ( name = formatname ( old ) ) == NULL ) { goto fail ; } for ( struct dirent * ep = pdst ; ep != NULL ; ep = ep -> parent ) { if ( ep == src ) { goto fail ; } } uint off ; elock ( src ) ; srclock = 1 ; elock ( pdst ) ; dst = dirlookup ( pdst , name , & off ) ; if ( dst != NULL ) { eunlock ( pdst ) ; if ( src == dst ) { goto fail ; } else if ( src -> attribute & dst -> attribute & ATTR_DIRECTORY ) { elock ( dst ) ; if ( ! isdirempty ( dst ) ) { eunlock ( dst ) ; goto fail ; } elock ( pdst ) ; } else { goto fail ; } } if ( dst ) { eremove ( dst ) ; eunlock ( dst ) ; } memmove ( src -> filename , name , FAT32_MAX_FILENAME ) ; emake ( pdst , src , off ) ; if ( src -> parent != pdst ) { eunlock ( pdst ) ; elock ( src -> parent ) ; } eremove ( src ) ; eunlock ( src -> parent ) ; struct dirent * psrc = src -> parent ; src -> parent = edup ( pdst ) ; src -> off = off ; src -> valid = 1 ; eunlock ( src ) ; eput ( psrc ) ; if ( dst ) { eput ( dst ) ; } eput ( pdst ) ; eput ( src ) ; return 0 ; fail : if ( srclock ) eunlock ( src ) ; if ( dst ) eput ( dst ) ; if ( pdst ) eput ( pdst ) ; if ( src ) eput ( src ) ; return -1 ; }
Must hold too many locks at a time!
Must hold too many locks at a time!
// src doesn't exist || dst parent doesn't exist || illegal new name // In what universe can we move a directory into its child? // must hold child's lock before acquiring parent's, because we do so in other similar cases // it's ok to overwrite an empty dir // src is not a dir || dst exists and is not an dir // src must not be root, or it won't pass the for-loop test