[project @ 2000-01-17 12:30:07 by simonmar]
[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.5 1999/09/30 12:35:50 sof 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 #if defined(mingw32_TARGET_OS) && !defined(O_NOCTTY)
25 #define O_NOCTTY 0
26 #endif
27
28
29 StgInt
30 renameFile(opath, npath)
31 StgByteArray opath;
32 StgByteArray npath;
33 {
34     struct stat sb;
35     int fd;
36     int created = 0;
37
38     /* Check for a non-directory source */
39     while (stat(opath, &sb) != 0) {
40         if (errno != EINTR) {
41             cvtErrno();
42             stdErrno();
43             return -1;
44         }
45     }
46     if (S_ISDIR(sb.st_mode)) {
47         ghc_errtype = ERR_INAPPROPRIATETYPE;
48         ghc_errstr = "file is a directory";
49         return -1;
50     }
51
52     /* Ensure a non-directory destination */
53
54     /* First try to open without creating */
55     while ((fd = open(npath, O_RDONLY | O_NOCTTY, 0)) < 0) {
56         if (errno == ENOENT) {
57             /* Now try to create it */
58             while ((fd = open(npath, O_RDONLY | O_NOCTTY | O_CREAT | O_EXCL, 0)) < 0) {
59                 if (errno == EEXIST) {
60                     /* Race detected; go back and open without creating it */
61                     break;
62                 } else if (errno != EINTR) {
63                     cvtErrno();
64                     switch (ghc_errno) {
65                     default:
66                         stdErrno();
67                         break;
68                     case GHC_ENOENT:
69                     case GHC_ENOTDIR:
70                         ghc_errtype = ERR_NOSUCHTHING;
71                         ghc_errstr = "no path to file";
72                         break;
73                     case GHC_EINVAL:
74                         ghc_errtype = ERR_PERMISSIONDENIED;
75                         ghc_errstr = "unsupported owner or group";
76                         break;
77                     }
78                     return -1;
79                 }
80             }
81             if (fd >= 0) {
82                 created = 1;
83                 break;
84             }
85         } else if (errno != EINTR) {
86             cvtErrno();
87             switch (ghc_errno) {
88             default:
89                 stdErrno();
90                 break;
91             case GHC_ENOTDIR:
92                 ghc_errtype = ERR_NOSUCHTHING;
93                 ghc_errstr = "no path to file";
94                 break;
95             case GHC_EINVAL:
96                 ghc_errtype = ERR_PERMISSIONDENIED;
97                 ghc_errstr = "unsupported owner or group";
98                 break;
99             }
100             return -1;
101         }
102     }
103
104     /* Make sure that we aren't looking at a directory */
105
106     while (fstat(fd, &sb) < 0) {
107         /* highly unlikely */
108         if (errno != EINTR) {
109             cvtErrno();
110             if (created)
111                 (void) unlink(npath);
112             (void) close(fd);
113             return -1;
114         }
115     }
116     if (S_ISDIR(sb.st_mode)) {
117         ghc_errtype = ERR_INAPPROPRIATETYPE;
118         ghc_errstr = "destination is a directory";
119         /* We can't have created it in this case. */
120         (void) close(fd);
121         return -1;
122     }
123
124     while(rename(opath, npath) != 0) {
125         if (errno != EINTR) {
126             cvtErrno();
127             stdErrno();
128             if (created)
129                 (void) unlink(npath);
130             (void) close(fd);
131             return -1;
132         }
133     }
134
135     close(fd);    
136     return 0;
137 }