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