#ifdef AFS_SALSRV_ENV
#include <pthread.h>
#include <afs/work_queue.h>
-#include <afs/thread_pool.h>
#include <vol/vol-salvage.h>
#endif
int Testing=0;
+static void namei_UnlockLinkCount(FdHandle_t * fdP, Inode ino);
afs_sfsize_t
namei_iread(IHandle_t * h, afs_foff_t offset, char *buf, afs_fsize_t size)
namei_ViceREADME(char *partition)
{
char filename[32];
- int fd;
+ int fd, len, e = 0;
/* Create the inode directory if we're starting for the first time */
snprintf(filename, sizeof filename, "%s" OS_DIRSEP "%s", partition,
partition, INODEDIR);
fd = OS_OPEN(filename, O_WRONLY | O_CREAT | O_TRUNC, 0444);
if (fd != INVALID_FD) {
- (void)OS_WRITE(fd, VICE_README, strlen(VICE_README));
+ len = strlen(VICE_README);
+ if (OS_WRITE(fd, VICE_README, len) != len)
+ e = errno;
OS_CLOSE(fd);
+ if (e)
+ errno = e;
}
return (errno);
}
memset((void *)&tmp, 0, sizeof(IHandle_t));
memset(&tfd, 0, sizeof(FdHandle_t));
+ ih_PkgDefaults();
+
tmp.ih_dev = nt_DriveToDev(part);
if (tmp.ih_dev == -1) {
errno = EINVAL;
#else /* !AFS_NT40_ENV */
Inode
icreate(IHandle_t * lh, char *part, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4,
- FD_t *afd, Inode *ainode)
+ IHandle_t **a_ih)
{
namei_t name;
int fd = INVALID_FD;
int code = 0;
int created_dir = 0;
IHandle_t tmp;
+ IHandle_t *realh = NULL;
FdHandle_t *fdP;
- FdHandle_t tfd;
int tag;
int ogm_parm;
memset((void *)&tmp, 0, sizeof(IHandle_t));
- memset(&tfd, 0, sizeof(FdHandle_t));
+
+ ih_PkgDefaults();
tmp.ih_dev = volutil_GetPartitionID(part);
if (tmp.ih_dev == -1) {
goto bad;
}
+ IH_INIT(realh, tmp.ih_dev, tmp.ih_vid, tmp.ih_ino);
+ fdP = ih_attachfd(realh, fd);
+
+ /* ih_attachfd can only return NULL if we give it an invalid fd; our fd
+ * must be valid by this point. */
+ opr_Assert(fdP);
+
if (p2 == (afs_uint32)-1 && p3 == VI_LINKTABLE) {
- /* hack at tmp to setup for set link count call. */
- memset((void *)&tfd, 0, sizeof(FdHandle_t)); /* minimalistic still, but a little cleaner */
- tfd.fd_ih = &tmp;
- tfd.fd_fd = fd;
- code = namei_SetLinkCount(&tfd, (Inode) 0, 1, 0);
+ code = namei_SetLinkCount(fdP, (Inode) 0, 1, 0);
}
+ FDH_CLOSE(fdP);
+
bad:
if (code || (fd == INVALID_FD)) {
if (p2 != -1) {
FDH_CLOSE(fdP);
}
}
+ IH_RELEASE(realh);
}
- *afd = fd;
- *ainode = tmp.ih_ino;
+ *a_ih = realh;
return code;
}
namei_icreate(IHandle_t * lh, char *part,
afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4)
{
- Inode ino = 0;
- int fd = INVALID_FD;
+ Inode ino;
+ IHandle_t *ihP = NULL;
int code;
- code = icreate(lh, part, p1, p2, p3, p4, &fd, &ino);
- if (fd != INVALID_FD) {
- close(fd);
+ code = icreate(lh, part, p1, p2, p3, p4, &ihP);
+ if (code || !ihP) {
+ opr_Assert(!ihP);
+ ino = -1;
+ } else {
+ ino = ihP->ih_ino;
+ IH_RELEASE(ihP);
}
- return (code || (fd == INVALID_FD)) ? (Inode) - 1 : ino;
+ return ino;
}
IHandle_t *
namei_icreate_init(IHandle_t * lh, int dev, char *part,
afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4)
{
- Inode ino = 0;
- int fd = INVALID_FD;
int code;
- IHandle_t *ihP;
- FdHandle_t *fdP;
+ IHandle_t *ihP = NULL;
- code = icreate(lh, part, p1, p2, p3, p4, &fd, &ino);
- if (fd == INVALID_FD) {
- return NULL;
- }
+ code = icreate(lh, part, p1, p2, p3, p4, &ihP);
if (code) {
- close(fd);
- return NULL;
+ opr_Assert(!ihP);
}
-
- IH_INIT(ihP, dev, p1, ino);
- fdP = ih_attachfd(ihP, fd);
- if (!fdP) {
- close(fd);
- } else {
- FDH_CLOSE(fdP);
- }
-
return ihP;
}
#endif
}
count--;
- if (namei_SetLinkCount(fdP, (Inode) 0, count < 0 ? 0 : count, 1) <
- 0) {
- FDH_REALLYCLOSE(fdP);
- IH_RELEASE(tmp);
- return -1;
- }
-
if (count > 0) {
+ /* if our count is non-zero, we just set our new linkcount and
+ * return. But if our count is 0, don't bother updating the
+ * linktable, since we're about to delete the link table,
+ * below. */
+ if (namei_SetLinkCount(fdP, (Inode) 0, count < 0 ? 0 : count, 1) < 0) {
+ FDH_REALLYCLOSE(fdP);
+ IH_RELEASE(tmp);
+ return -1;
+ }
+
FDH_CLOSE(fdP);
IH_RELEASE(tmp);
return 0;
}
+
+ namei_UnlockLinkCount(fdP, (Inode) 0);
}
+ /* We should IH_REALLYCLOSE right before deleting the special file from
+ * disk, to ensure that somebody else cannot create a special inode,
+ * then IH_OPEN that special inode and get back a cached fd for the
+ * file we are deleting here (instead of an fd for the file they just
+ * created). */
+ IH_REALLYCLOSE(tmp);
+ FDH_REALLYCLOSE(fdP);
+ IH_RELEASE(tmp);
+
if ((code = OS_UNLINK(name.n_path)) == 0) {
if (type == VI_LINKTABLE) {
/* Try to remove directory. If it fails, that's ok.
(void)namei_RemoveDataDirectories(&name);
}
}
- FDH_REALLYCLOSE(fdP);
- IH_RELEASE(tmp);
} else {
/* Get a file descriptor handle for this Inode */
fdP = IH_OPEN(ih);
if (afs_stat(name.n_path, &tstat) < 0)
return EIO;
if (tstat.st_nlink > 1) { /* do a copy on write */
- char path[259];
+ char path[NAMEI_PATH_LEN + 4];
char *buf;
afs_size_t size;
ssize_t tlen;
NAMEI_GLC_UNLOCK;
goto bad_getLinkByte;
}
- FDH_TRUNC(h, offset+sizeof(row));
+ if (FDH_TRUNC(h, offset+sizeof(row))) {
+ NAMEI_GLC_UNLOCK;
+ goto bad_getLinkByte;
+ }
row = 1 << index;
rc = FDH_PWRITE(h, (char *)&row, sizeof(row), offset);
NAMEI_GLC_UNLOCK;
return -1;
}
-int
-namei_SetNonZLC(FdHandle_t * h, Inode ino)
-{
- return namei_GetLinkCount(h, ino, 0, 1, 0);
-}
-
/* Return a free column index for this vnode. */
static int
GetFreeTag(IHandle_t * ih, int vno)
if (fdP == NULL)
return -1;
+ offset = (vno << LINKTABLE_SHIFT) + 8; /* * 2 + sizeof stamp */
+
/* Only one manipulates at a time. */
if (FDH_LOCKFILE(fdP, offset) != 0) {
FDH_REALLYCLOSE(fdP);
return -1;
}
- offset = (vno << LINKTABLE_SHIFT) + 8; /* * 2 + sizeof stamp */
-
nBytes = FDH_PREAD(fdP, (char *)&row, sizeof(row), offset);
if (nBytes != sizeof(row)) {
if (nBytes != 0)
return (int)nBytes;
}
+static void
+namei_UnlockLinkCount(FdHandle_t * fdP, Inode ino)
+{
+ afs_foff_t offset;
+ int index;
+
+ namei_GetLCOffsetAndIndexFromIno(ino, &offset, &index);
+
+ FDH_UNLOCKFILE(fdP, offset);
+}
+
/* ListViceInodes - write inode data to a results file. */
static int DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
- VolumeId volid);
+ IHandle_t *myIH);
static int DecodeVolumeName(char *name, VolumeId *vid);
static int namei_ListAFSSubDirs(IHandle_t * dirIH,
int (*write_fun) (FD_t,
int ret = 0;
struct ViceInodeInfo info;
- if (DecodeInode(path1, dname, &info, myIH->ih_vid) < 0) {
+ if (DecodeInode(path1, dname, &info, myIH) < 0) {
ret = 0;
goto error;
}
"(dir_vgid=%" AFS_VOLID_FMT ", inode_vgid=%" AFS_VOLID_FMT ")\n",
path1, dname, afs_printable_VolumeId_lu(myIH->ih_vid),
afs_printable_VolumeId_lu(info.u.param[0]));
+ /* We need to set the linkCount to _something_, so linkCount
+ * doesn't just contain stack garbage. Set it to 0, so in case
+ * the salvager or whatever our caller is does try to process
+ * this like a normal file, we won't try to INC or DEC it. */
+ info.linkCount = 0;
} else {
char path2[512];
/* Open this handle */
int dirl; /* Windows-only (one level hash dir) */
#endif
- if (DecodeInode(path3, dname, &info, myIH->ih_vid) < 0) {
+ if (DecodeInode(path3, dname, &info, myIH) < 0) {
goto error;
}
struct rx_queue resultlist;
#endif
+ memset(&linkHandle, 0, sizeof(linkHandle));
+
namei_HandleToVolDir(&name, &myIH);
strlcpy(path1, name.n_path, sizeof(path1));
#ifndef AFS_NT40_ENV /* This level missing on Windows */
/* Now we've got a next level subdir. */
- snprintf(path2, sizeof(path2), "%s" OS_DIRSEP "%s",
- path1, dp1->d_name);
+ code = snprintf(path2, sizeof(path2), "%s" OS_DIRSEP "%s",
+ path1, dp1->d_name);
+ if (code < 0 || code >= sizeof(path2)) {
+ /* error, or truncated */
+ closedir(dirp1);
+ ret = -1;
+ goto error;
+ }
dirp2 = opendir(path2);
if (dirp2) {
while ((dp2 = readdir(dirp2))) {
continue;
/* Now we've got to the actual data */
- snprintf(path3, sizeof(path3), "%s" OS_DIRSEP "%s",
- path2, dp2->d_name);
+ code = snprintf(path3, sizeof(path3), "%s" OS_DIRSEP "%s",
+ path2, dp2->d_name);
#else
/* Now we've got to the actual data */
- snprintf(path3, sizeof(path3), "%s" OS_DIRSEP "%s",
- path1, dp1->d_name);
+ code = snprintf(path3, sizeof(path3), "%s" OS_DIRSEP "%s",
+ path1, dp1->d_name);
+#endif
+ if (code < 0 || code >= sizeof(path3)) {
+ /* error, or truncated */
+#ifndef AFS_NT40_ENV
+ closedir(dirp2);
#endif
+ closedir(dirp1);
+ ret = -1;
+ goto error;
+ }
dirp3 = opendir(path3);
if (dirp3) {
while ((dp3 = readdir(dirp3))) {
#ifdef AFS_NT40_ENV
static int
DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
- VolumeId volid)
+ IHandle_t *myIH)
{
char fpath[512];
int tag, vno;
char stmp[16];
FdHandle_t linkHandle;
char dirl;
+ VolumeId volid = myIH->ih_vid;
+
+ memset(&linkHandle, 0, sizeof(linkHandle));
snprintf(fpath, sizeof(fpath), "%s" OS_DIRSEP "%s", dpath, name);
#else
static int
DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
- VolumeId volid)
+ IHandle_t *myIH)
{
char fpath[512];
struct afs_stat_st status;
+ struct afs_stat_st checkstatus;
int parm, tag;
lb64_string_t check;
+ VolumeId volid = myIH->ih_vid;
+ IHandle_t tmpih;
+ namei_t nameiname;
snprintf(fpath, sizeof(fpath), "%s" OS_DIRSEP "%s", dpath, name);
if (strcmp(name, check))
return -1;
+ /* Check if the _full_ path is correct, to ensure we can actually open this
+ * file later. Otherwise, the salvager can choke. */
+ memset(&tmpih, 0, sizeof(tmpih));
+ tmpih.ih_dev = myIH->ih_dev;
+ tmpih.ih_vid = myIH->ih_vid;
+ tmpih.ih_ino = info->inodeNumber;
+ namei_HandleToName(&nameiname, &tmpih);
+ if ((afs_stat(nameiname.n_path, &checkstatus) < 0) ||
+ checkstatus.st_ino != status.st_ino ||
+ checkstatus.st_size != status.st_size) {
+ static int logged;
+ /* log something for this case, since this means the filename looks
+ * like a valid inode, but it's just in the wrong place. That's pretty
+ * strange. */
+ if (!logged) {
+ logged = 1;
+ Log("Note:\n");
+ Log(" Seemingly-misplaced files have been found, which I am\n");
+ Log(" ignoring for now. If you cannot salvage the relevant volume,\n");
+ Log(" you may try manually moving them to their correct location.\n");
+ Log(" If the relevant volume seems fine, and these files do not\n");
+ Log(" appear to contain important data, you can probably manually\n");
+ Log(" delete them, or leave them alone. Contact your local OpenAFS\n");
+ Log(" expert if you are unsure.\n");
+ }
+ Log("Ignoring misplaced file in volume group %u: %s (should be %s)\n",
+ (unsigned)myIH->ih_vid, fpath, nameiname.n_path);
+ return -1;
+ }
+
if ((info->inodeNumber & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
parm = ((info->inodeNumber >> NAMEI_UNIQSHIFT) & NAMEI_UNIQMASK);
tag = (int)((info->inodeNumber >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
if (*dp->d_name == '.')
continue;
#endif
- if (DecodeInode(dir_name, dp->d_name, &info, ih->ih_vid) < 0) {
+ if (DecodeInode(dir_name, dp->d_name, &info, ih) < 0) {
Log("1 namei_ConvertROtoRWvolume: DecodeInode failed for %s" OS_DIRSEP "%s\n",
dir_name, dp->d_name);
closedir(dirp);
t_ih.ih_dev = ih->ih_dev;
t_ih.ih_vid = ih->ih_vid;
- snprintf(oldpath, sizeof oldpath, "%s" OS_DIRSEP "%s", dir_name,
- infoName);
+ code = snprintf(oldpath, sizeof oldpath, "%s" OS_DIRSEP "%s", dir_name,
+ infoName);
+ if (code < 0 || code >= sizeof(oldpath)) {
+ /* error, or truncated */
+ code = -1;
+ goto done;
+ }
fd = OS_OPEN(oldpath, O_RDWR, 0);
if (fd == INVALID_FD) {
Log("1 namei_ConvertROtoRWvolume: could not open RO info file: %s\n",
t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_SMALLINDEX);
namei_HandleToName(&n, &t_ih);
- snprintf(newpath, sizeof newpath, "%s" OS_DIRSEP "%s", dir_name,
- smallName);
+ code = snprintf(newpath, sizeof newpath, "%s" OS_DIRSEP "%s", dir_name,
+ smallName);
+ if (code < 0 || code >= sizeof(newpath)) {
+ /* error, or truncated */
+ code = -1;
+ goto done;
+ }
fd = OS_OPEN(newpath, O_RDWR, 0);
if (fd == INVALID_FD) {
Log("1 namei_ConvertROtoRWvolume: could not open SmallIndex file: %s\n", newpath);
#ifdef AFS_NT40_ENV
MoveFileEx(n.n_path, newpath, MOVEFILE_WRITE_THROUGH);
#else
- link(newpath, n.n_path);
+ if (link(newpath, n.n_path)) {
+ Log("1 namei_ConvertROtoRWvolume: could not move SmallIndex file: %s\n", n.n_path);
+ code = -1;
+ goto done;
+ }
OS_UNLINK(newpath);
#endif
t_ih.ih_ino = namei_MakeSpecIno(ih->ih_vid, VI_LARGEINDEX);
namei_HandleToName(&n, &t_ih);
- snprintf(newpath, sizeof newpath, "%s" OS_DIRSEP "%s", dir_name,
- largeName);
+ code = snprintf(newpath, sizeof newpath, "%s" OS_DIRSEP "%s", dir_name,
+ largeName);
+ if (code < 0 || code >= sizeof(newpath)) {
+ /* error, or truncated */
+ code = -1;
+ goto done;
+ }
fd = OS_OPEN(newpath, O_RDWR, 0);
if (fd == INVALID_FD) {
Log("1 namei_ConvertROtoRWvolume: could not open LargeIndex file: %s\n", newpath);
#ifdef AFS_NT40_ENV
MoveFileEx(n.n_path, newpath, MOVEFILE_WRITE_THROUGH);
#else
- link(newpath, n.n_path);
+ if (link(newpath, n.n_path)) {
+ Log("1 namei_ConvertROtoRWvolume: could not move LargeIndex file: %s\n", n.n_path);
+ code = -1;
+ goto done;
+ }
OS_UNLINK(newpath);
#endif
FSYNC_VolOp(volumeId, pname, FSYNC_VOL_DONE, 0, NULL);
FSYNC_VolOp(h.id, pname, FSYNC_VOL_ON, 0, NULL);
+ code = 0;
done:
# ifdef AFS_DEMAND_ATTACH_FS
if (locktype) {
}
#endif
+/**
+ * Remove empty directories associated with the volume received
+ * as an argument.
+ *
+ * @param[in] pname vice partition path
+ * @param[in] vid volume id
+ *
+ * @return 0 on success
+ */
+int
+namei_RemoveDirectories(char *pname, afs_int32 vid)
+{
+ IHandle_t dirIH;
+ namei_t name;
+
+ memset(&dirIH, 0, sizeof(dirIH));
+
+ dirIH.ih_vid = vid;
+
+#ifdef AFS_NT40_ENV
+ dirIH.ih_dev = nt_DriveToDev(pname);
+#else
+ dirIH.ih_dev = volutil_GetPartitionID(pname);
+#endif
+ if (dirIH.ih_dev == -1) {
+ return -1;
+ }
+
+ namei_HandleToVolDir(&name, &dirIH);
+
+ return namei_RemoveDataDirectories(&name);
+}
+
#endif /* AFS_NAMEI_ENV */