[project @ 1998-04-10 10:49:39 by simonm]
[ghc-hetmet.git] / ghc / lib / std / cbits / renameFile.c
1 /* 
2  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
3  *
4  * $Id: renameFile.c,v 1.1 1998/04/10 10:54:48 simonm Exp $
5  *
6  * renameFile Runtime Support
7  */
8
9 #include "Rts.h"
10 #include "stgio.h"
11
12 #ifdef HAVE_SYS_TYPES_H
13 #include <sys/types.h>
14 #endif
15
16 #ifdef HAVE_SYS_STAT_H
17 #include <sys/stat.h>
18 #endif
19
20 #ifdef HAVE_FCNTL_H
21 #include <fcntl.h>
22 #endif
23
24 StgInt
25 renameFile(StgByteArray opath, StgByteArray npath)
26 {
27     struct stat sb;
28     int fd;
29     int created = 0;
30
31     /* Check for a non-directory source */
32     while (stat(opath, &sb) != 0) {
33         if (errno != EINTR) {
34             cvtErrno();
35             stdErrno();
36             return -1;
37         }
38     }
39     if (S_ISDIR(sb.st_mode)) {
40         ghc_errtype = ERR_INAPPROPRIATETYPE;
41         ghc_errstr = "file is a directory";
42         return -1;
43     }
44
45     /* Ensure a non-directory destination */
46
47     /* First try to open without creating */
48     while ((fd = open(npath, O_RDONLY | O_NOCTTY, 0)) < 0) {
49         if (errno == ENOENT) {
50             /* Now try to create it */
51             while ((fd = open(npath, O_RDONLY | O_NOCTTY | O_CREAT | O_EXCL, 0)) < 0) {
52                 if (errno == EEXIST) {
53                     /* Race detected; go back and open without creating it */
54                     break;
55                 } else if (errno != EINTR) {
56                     cvtErrno();
57                     switch (ghc_errno) {
58                     default:
59                         stdErrno();
60                         break;
61                     case GHC_ENOENT:
62                     case GHC_ENOTDIR:
63                         ghc_errtype = ERR_NOSUCHTHING;
64                         ghc_errstr = "no path to file";
65                         break;
66                     case GHC_EINVAL:
67                         ghc_errtype = ERR_PERMISSIONDENIED;
68                         ghc_errstr = "unsupported owner or group";
69                         break;
70                     }
71                     return -1;
72                 }
73             }
74             if (fd >= 0) {
75                 created = 1;
76                 break;
77             }
78         } else if (errno != EINTR) {
79             cvtErrno();
80             switch (ghc_errno) {
81             default:
82                 stdErrno();
83                 break;
84             case GHC_ENOTDIR:
85                 ghc_errtype = ERR_NOSUCHTHING;
86                 ghc_errstr = "no path to file";
87                 break;
88             case GHC_EINVAL:
89                 ghc_errtype = ERR_PERMISSIONDENIED;
90                 ghc_errstr = "unsupported owner or group";
91                 break;
92             }
93             return -1;
94         }
95     }
96
97     /* Make sure that we aren't looking at a directory */
98
99     while (fstat(fd, &sb) < 0) {
100         /* highly unlikely */
101         if (errno != EINTR) {
102             cvtErrno();
103             if (created)
104                 (void) unlink(npath);
105             (void) close(fd);
106             return -1;
107         }
108     }
109     if (S_ISDIR(sb.st_mode)) {
110         ghc_errtype = ERR_INAPPROPRIATETYPE;
111         ghc_errstr = "destination is a directory";
112         /* We can't have created it in this case. */
113         (void) close(fd);
114         return -1;
115     }
116
117     while(rename(opath, npath) != 0) {
118         if (errno != EINTR) {
119             cvtErrno();
120             stdErrno();
121             if (created)
122                 (void) unlink(npath);
123             (void) close(fd);
124             return -1;
125         }
126     }
127
128     close(fd);    
129     return 0;
130 }