2 * unix_apply.c - Code to apply files from a WIM image on UNIX.
6 * Copyright (C) 2012, 2013 Eric Biggers
8 * This file is part of wimlib, a library for working with WIM files.
10 * wimlib is free software; you can redistribute it and/or modify it under the
11 * terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 3 of the License, or (at your option)
15 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
16 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17 * A PARTICULAR PURPOSE. See the GNU General Public License for more
20 * You should have received a copy of the GNU General Public License
21 * along with wimlib; if not, see http://www.gnu.org/licenses/.
30 #include "wimlib/apply.h"
31 #include "wimlib/error.h"
32 #include "wimlib/lookup_table.h"
33 #include "wimlib/resource.h"
34 #include "wimlib/timestamp.h"
40 #include <sys/types.h>
48 unix_start_extract(const char *target, struct apply_ctx *ctx)
50 ctx->supported_features.hard_links = 1;
51 ctx->supported_features.symlink_reparse_points = 1;
52 ctx->supported_features.unix_data = 1;
57 unix_create_file(const char *path, struct apply_ctx *ctx)
59 int fd = open(path, O_TRUNC | O_CREAT | O_WRONLY, 0644);
61 return WIMLIB_ERR_OPEN;
67 unix_create_directory(const tchar *path, struct apply_ctx *ctx)
71 if (mkdir(path, 0755)) {
73 return WIMLIB_ERR_MKDIR;
74 if (lstat(path, &stbuf))
75 return WIMLIB_ERR_STAT;
77 if (!S_ISDIR(stbuf.st_mode))
78 return WIMLIB_ERR_NOTDIR;
84 unix_makelink(const tchar *oldpath, const tchar *newpath,
85 int (*makelink)(const tchar *oldpath, const tchar *newpath))
87 if ((*makelink)(oldpath, newpath)) {
88 if (errno == EEXIST) {
90 return WIMLIB_ERR_LINK;
91 if ((*makelink)(oldpath, newpath))
92 return WIMLIB_ERR_LINK;
95 return WIMLIB_ERR_LINK;
100 unix_create_hardlink(const tchar *oldpath, const tchar *newpath,
101 struct apply_ctx *ctx)
103 return unix_makelink(oldpath, newpath, link);
107 unix_create_symlink(const tchar *oldpath, const tchar *newpath,
108 struct apply_ctx *ctx)
110 return unix_makelink(oldpath, newpath, symlink);
114 unix_extract_unnamed_stream(const tchar *path,
115 struct wim_lookup_table_entry *lte,
116 struct apply_ctx *ctx)
122 raw_fd = open(path, O_WRONLY | O_TRUNC);
124 return WIMLIB_ERR_OPEN;
125 filedes_init(&fd, raw_fd);
126 ret = extract_wim_resource_to_fd(lte, &fd, wim_resource_size(lte));
127 if (filedes_close(&fd) && !ret)
128 ret = WIMLIB_ERR_WRITE;
133 unix_set_unix_data(const tchar *path, const struct wimlib_unix_data *data,
134 struct apply_ctx *ctx)
138 if (lstat(path, &stbuf))
139 return WIMLIB_ERR_SET_SECURITY;
140 if (!S_ISLNK(stbuf.st_mode))
141 if (chmod(path, data->mode))
142 return WIMLIB_ERR_SET_SECURITY;
143 if (lchown(path, data->uid, data->gid))
144 return WIMLIB_ERR_SET_SECURITY;
149 unix_set_timestamps(const tchar *path, u64 creation_time, u64 last_write_time,
150 u64 last_access_time, struct apply_ctx *ctx)
154 #ifdef HAVE_UTIMENSAT
155 /* Convert the WIM timestamps, which are accurate to 100 nanoseconds,
156 * into `struct timespec's for passing to utimensat(), which is accurate
157 * to 1 nanosecond. */
159 struct timespec ts[2];
160 ts[0] = wim_timestamp_to_timespec(last_access_time);
161 ts[1] = wim_timestamp_to_timespec(last_write_time);
162 ret = utimensat(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW);
170 /* utimensat() not implemented or not available */
172 /* Convert the WIM timestamps, which are accurate to 100
173 * nanoseconds, into `struct timeval's for passing to lutimes(),
174 * which is accurate to 1 microsecond. */
175 struct timeval tv[2];
176 tv[0] = wim_timestamp_to_timeval(last_access_time);
177 tv[1] = wim_timestamp_to_timeval(last_write_time);
178 ret = lutimes(path, tv);
185 /* utimensat() and lutimes() both not implemented or not
188 /* Convert the WIM timestamps, which are accurate to 100
189 * nanoseconds, into a `struct utimbuf's for passing to
190 * utime(), which is accurate to 1 second. */
192 buf.actime = wim_timestamp_to_unix(last_access_time);
193 buf.modtime = wim_timestamp_to_unix(last_write_time);
194 ret = utime(path, &buf);
198 return WIMLIB_ERR_SET_TIMESTAMPS;
202 const struct apply_operations unix_apply_ops = {
205 .start_extract = unix_start_extract,
206 .create_file = unix_create_file,
207 .create_directory = unix_create_directory,
208 .create_hardlink = unix_create_hardlink,
209 .create_symlink = unix_create_symlink,
210 .extract_unnamed_stream = unix_extract_unnamed_stream,
211 .set_unix_data = unix_set_unix_data,
212 .set_timestamps = unix_set_timestamps,
214 .path_separator = '/',
215 .path_max = PATH_MAX,
217 .requires_target_in_paths = 1,
218 .supports_case_sensitive_filenames = 1,
221 #endif /* !__WIN32__ */