int safe_rename (const char *src, const char *target) { struct stat ssb, tsb; if (!src || !target) return -1; if (link (src, target) != 0) { /* * Coda does not allow cross-directory links, but tells * us it's a cross-filesystem linking attempt. * * However, the Coda rename call is allegedly safe to use. * * With other file systems, rename should just fail when * the files reside on different file systems, so it's safe * to try it here. * */ if (errno == EXDEV) return rename (src, target); return -1; } /* * Stat both links and check if they are equal. */ if (stat (src, &ssb) == -1) { return -1; } if (stat (target, &tsb) == -1) { return -1; } /* * pretend that the link failed because the target file * did already exist. */ if (compare_stat (&ssb, &tsb) == -1) { errno = EEXIST; return -1; } /* * Unlink the original link. Should we really ignore the return * value here? XXX */ unlink (src); return 0; }
int io_open (const char *path, int flags, int u) { struct stat osb, nsb; int fd; if (u > 0) umask (u); if ((fd = open (path, flags, 0666)) < 0) return fd; /* make sure the file is not symlink */ if (lstat (path, &osb) < 0 || fstat (fd, &nsb) < 0 || compare_stat (&osb, &nsb) == -1) { close (fd); return (-1); } return (fd); }
int safe_open (const char *path, int flags) { struct stat osb, nsb; int fd; #if defined(__linux__) if ((fd = opennfs (path, flags, 0600)) < 0) return fd; #else if (flags & O_EXCL) { char safe_file[_POSIX_PATH_MAX]; char safe_dir[_POSIX_PATH_MAX]; if (mutt_mkwrapdir (path, safe_file, sizeof (safe_file), safe_dir, sizeof (safe_dir)) == -1) return -1; if ((fd = open (safe_file, flags, 0600)) < 0) { rmdir (safe_dir); return fd; } /* NFS and I believe cygwin do not handle movement of open files well */ close (fd); if (mutt_put_file_in_place (path, safe_file, safe_dir) == -1) return -1; } if ((fd = open (path, flags & ~O_EXCL, 0600)) < 0) return fd; #endif /* make sure the file is not symlink */ if (lstat (path, &osb) < 0 || fstat (fd, &nsb) < 0 || compare_stat(&osb, &nsb) == -1) { /* dprint (1, (debugfile, "safe_open(): %s is a symlink!\n", path)); */ close (fd); return (-1); } return (fd); }
int safe_open (const char *path, int flags) { struct stat osb, nsb; int fd; umask (Umask); if ((fd = open (path, flags, 0666)) < 0) return fd; /* make sure the file is not symlink */ if (lstat (path, &osb) < 0 || fstat (fd, &nsb) < 0 || compare_stat (&osb, &nsb) == -1) { debug_print (1, ("%s is a symlink!\n", path)); close (fd); return (-1); } return (fd); }
int safe_open (const char *path, int flags) { struct stat osb, nsb; int fd; if ((fd = open (path, flags, 0600)) < 0) return fd; /* make sure the file is not symlink */ if (lstat (path, &osb) < 0 || fstat (fd, &nsb) < 0 || compare_stat(&osb, &nsb) == -1) { /* dprint (1, (debugfile, "safe_open(): %s is a symlink!\n", path)); */ close (fd); return (-1); } return (fd); }
int safe_symlink(const char *oldpath, const char *newpath) { struct stat osb, nsb; if(!oldpath || !newpath) return -1; if(unlink(newpath) == -1 && errno != ENOENT) return -1; if (oldpath[0] == '/') { if (symlink (oldpath, newpath) == -1) return -1; } else { char abs_oldpath[_POSIX_PATH_MAX]; if ((getcwd (abs_oldpath, sizeof abs_oldpath) == NULL) || (strlen (abs_oldpath) + 1 + strlen (oldpath) + 1 > sizeof abs_oldpath)) return -1; strcat (abs_oldpath, "/"); /* __STRCAT_CHECKED__ */ strcat (abs_oldpath, oldpath); /* __STRCAT_CHECKED__ */ if (symlink (abs_oldpath, newpath) == -1) return -1; } if(stat(oldpath, &osb) == -1 || stat(newpath, &nsb) == -1 || compare_stat(&osb, &nsb) == -1) { unlink(newpath); return -1; } return 0; }
int safe_rename (const char *src, const char *target) { struct stat ssb, tsb; if (!src || !target) return -1; if (link (src, target) != 0) { /* * Coda does not allow cross-directory links, but tells * us it's a cross-filesystem linking attempt. * * However, the Coda rename call is allegedly safe to use. * * With other file systems, rename should just fail when * the files reside on different file systems, so it's safe * to try it here. * */ dprint (1, (debugfile, "safe_rename: link (%s, %s) failed: %s (%d)\n", src, target, strerror (errno), errno)); /* * FUSE may return ENOSYS. VFAT may return EPERM. FreeBSD's * msdosfs may return EOPNOTSUPP. ENOTSUP can also appear. */ if (errno == EXDEV || errno == ENOSYS || errno == EPERM #ifdef ENOTSUP || errno == ENOTSUP #endif #ifdef EOPNOTSUPP || errno == EOPNOTSUPP #endif ) { dprint (1, (debugfile, "safe_rename: trying rename...\n")); if (rename (src, target) == -1) { dprint (1, (debugfile, "safe_rename: rename (%s, %s) failed: %s (%d)\n", src, target, strerror (errno), errno)); return -1; } dprint (1, (debugfile, "safe_rename: rename succeeded.\n")); return 0; } return -1; } /* * Stat both links and check if they are equal. */ if (lstat (src, &ssb) == -1) { dprint (1, (debugfile, "safe_rename: can't stat %s: %s (%d)\n", src, strerror (errno), errno)); return -1; } if (lstat (target, &tsb) == -1) { dprint (1, (debugfile, "safe_rename: can't stat %s: %s (%d)\n", src, strerror (errno), errno)); return -1; } /* * pretend that the link failed because the target file * did already exist. */ if (compare_stat (&ssb, &tsb) == -1) { dprint (1, (debugfile, "safe_rename: stat blocks for %s and %s diverge; pretending EEXIST.\n", src, target)); errno = EEXIST; return -1; } /* * Unlink the original link. Should we really ignore the return * value here? XXX */ if (unlink (src) == -1) { dprint (1, (debugfile, "safe_rename: unlink (%s) failed: %s (%d)\n", src, strerror (errno), errno)); } return 0; }