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/resource.h"
33 #include "wimlib/timestamp.h"
34 #include "wimlib/unix_data.h"
40 #include <sys/types.h>
52 unix_start_extract(const char *target, struct apply_ctx *ctx)
54 ctx->supported_features.hard_links = 1;
55 ctx->supported_features.symlink_reparse_points = 1;
56 ctx->supported_features.unix_data = 1;
61 unix_create_file(const char *path, struct apply_ctx *ctx, u64 *cookie_ret)
63 int fd = open(path, O_TRUNC | O_CREAT | O_WRONLY | O_NOFOLLOW, 0644);
65 return WIMLIB_ERR_OPEN;
71 unix_create_directory(const tchar *path, struct apply_ctx *ctx, u64 *cookie_ret)
75 if (mkdir(path, 0755)) {
77 return WIMLIB_ERR_MKDIR;
78 if (lstat(path, &stbuf))
79 return WIMLIB_ERR_MKDIR;
81 if (!S_ISDIR(stbuf.st_mode))
82 return WIMLIB_ERR_MKDIR;
88 unix_makelink(const tchar *oldpath, const tchar *newpath,
89 int (*makelink)(const tchar *oldpath, const tchar *newpath))
91 if ((*makelink)(oldpath, newpath)) {
93 return WIMLIB_ERR_LINK;
95 return WIMLIB_ERR_LINK;
96 if ((*makelink)(oldpath, newpath))
97 return WIMLIB_ERR_LINK;
102 unix_create_hardlink(const tchar *oldpath, const tchar *newpath,
103 struct apply_ctx *ctx)
105 return unix_makelink(oldpath, newpath, link);
109 unix_create_symlink(const tchar *oldpath, const tchar *newpath,
110 struct apply_ctx *ctx)
112 return unix_makelink(oldpath, newpath, symlink);
116 unix_extract_unnamed_stream(file_spec_t file,
117 struct wim_lookup_table_entry *lte,
118 struct apply_ctx *ctx, struct wim_dentry *_ignore)
120 const char *path = file.path;
125 raw_fd = open(path, O_WRONLY | O_TRUNC | O_NOFOLLOW);
127 return WIMLIB_ERR_OPEN;
128 filedes_init(&fd, raw_fd);
129 ret = extract_full_stream_to_fd(lte, &fd);
130 if (filedes_close(&fd) && !ret)
131 ret = WIMLIB_ERR_WRITE;
136 unix_set_unix_data(const tchar *path, const struct wimlib_unix_data *data,
137 struct apply_ctx *ctx)
141 if (lstat(path, &stbuf))
142 return WIMLIB_ERR_SET_SECURITY;
143 if (!S_ISLNK(stbuf.st_mode))
144 if (chmod(path, data->mode))
145 return WIMLIB_ERR_SET_SECURITY;
146 if (lchown(path, data->uid, data->gid))
147 return WIMLIB_ERR_SET_SECURITY;
152 unix_set_timestamps(const tchar *path, u64 creation_time, u64 last_write_time,
153 u64 last_access_time, struct apply_ctx *ctx)
157 #ifdef HAVE_UTIMENSAT
158 /* Convert the WIM timestamps, which are accurate to 100 nanoseconds,
159 * into `struct timespec's for passing to utimensat(), which is accurate
160 * to 1 nanosecond. */
162 struct timespec ts[2];
163 ts[0] = wim_timestamp_to_timespec(last_access_time);
164 ts[1] = wim_timestamp_to_timespec(last_write_time);
165 ret = utimensat(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW);
173 /* utimensat() not implemented or not available */
175 /* Convert the WIM timestamps, which are accurate to 100
176 * nanoseconds, into `struct timeval's for passing to lutimes(),
177 * which is accurate to 1 microsecond. */
178 struct timeval tv[2];
179 tv[0] = wim_timestamp_to_timeval(last_access_time);
180 tv[1] = wim_timestamp_to_timeval(last_write_time);
181 ret = lutimes(path, tv);
188 /* utimensat() and lutimes() both not implemented or not
191 /* Convert the WIM timestamps, which are accurate to 100
192 * nanoseconds, into a `struct utimbuf's for passing to
193 * utime(), which is accurate to 1 second. */
195 buf.actime = wim_timestamp_to_unix(last_access_time);
196 buf.modtime = wim_timestamp_to_unix(last_write_time);
197 ret = utime(path, &buf);
201 return WIMLIB_ERR_SET_TIMESTAMPS;
205 const struct apply_operations unix_apply_ops = {
208 .start_extract = unix_start_extract,
209 .create_file = unix_create_file,
210 .create_directory = unix_create_directory,
211 .create_hardlink = unix_create_hardlink,
212 .create_symlink = unix_create_symlink,
213 .extract_unnamed_stream = unix_extract_unnamed_stream,
214 .set_unix_data = unix_set_unix_data,
215 .set_timestamps = unix_set_timestamps,
217 .path_separator = '/',
218 .path_max = PATH_MAX,
220 .requires_target_in_paths = 1,
221 .supports_case_sensitive_filenames = 1,
224 #endif /* !__WIN32__ */